Terminal · intermediate
Positional and special parameters
Positional parameters hold a script or function's arguments, while special parameters expose related state such as argument count, last status, process identity, and all arguments.
Why it matters
Handling these parameters correctly preserves argument boundaries and makes scripts validate their interface instead of silently operating on missing values.
Mental model
How to reason about positional and special parameters
The shell maintains an ordered argument vector addressed by $1 onward; $# counts it and quoted "$@" expands each original element as its own word.
Analogy
It is a numbered tray of sealed packages: quoted "$@" forwards every package without opening or merging it, while $# reports how many arrived.
Examples
See the boundary, not just the happy path
Worked example · Validate required arguments
if [ "$#" -ne 2 ]; then printf 'usage: %s SRC DST\n' "$0" >&2; exit 64; fi$# supplies the exact argument count, $0 identifies the invoked script, and the usage diagnostic is sent to stderr.
Worked example · Forward arguments intact
exec rsync -a -- "$@"Quoted "$@" produces one word per original argument, preserving empty arguments and spaces, while -- ends option parsing for supporting commands.
Avoid · Collapsed argument boundaries
for arg in $*; do printf '%s\n' "$arg"; doneUnquoted $* is subject to splitting and globbing, so original arguments containing spaces or patterns are not preserved.
Common mistakes
Misconceptions to remove early
Using unquoted $@
Without quotes, expanded arguments can undergo word splitting and filename expansion; use "$@" for ordinary forwarding.
Assuming $10 means argument ten everywhere
Use ${10} to delimit a multi-digit positional parameter; $10 may be parsed as $1 followed by literal 0.
Quick check
Can you predict the result?
1. Which expansion normally forwards every argument while preserving its boundary?
- • "$@"
- • $*
- • "$#"
2. What does $# represent?
Keep building