"$@", $* and shift
backup.sh should accept any number of folders: ./backup.sh ~/notes "My Photos" ~/code. You cannot write $1 $2 $3 when you do not know how many will come. Bash has two ways to say "all the arguments", and only one of them is safe.
The rule
"$@"keeps each argument whole;shiftdrops the first.
For the call ./backup.sh ~/notes "My Photos":
| Written as | Becomes |
|---|---|
"$@" |
two words: /home/asha/notes and My Photos |
"$*" |
one word: /home/asha/notes My Photos |
$@ or $* unquoted |
three words: /home/asha/notes, My, Photos |
"$@" is exactly what the caller typed, argument for argument. It is the right choice almost every time you pass arguments on to another command:
tar -czf "$archive" "$@""$*" is for when you want one string, such as a log message: echo "Arguments: $*".
shift throws away $1 and moves every other argument down one place. $# drops by one. shift 2 drops two. This is how a script peels off leading options before handling the rest:
label="$1" # save it first
shift # now "$@" is only the folders
tar -czf "$dest/$label.tar.gz" "$@"The shortcut
Picture the arguments as cards in a row. "$@" hands over the row, every card separate. "$*" tapes the cards into one strip. Unquoted, the cards are cut apart at every space. shift takes the first card off the table, so the others slide left.
Before shift
$1isweekly,$2is/home/asha/notes,$3isMy Photos, and$#is 3.
Drills
Answer fast — trust the rule.
A script is run as ./s "a b" c. How many words does "$@" expand to?
For the same call, ./s "a b" c, what does "$*" expand to?
For ./s "a b" c, how many words does unquoted $@ give?
A script gets x y z, runs shift, then echo "$1 $#". What prints?
Why must label="$1" come before shift?
Remember
"$@"keeps each argument whole;shiftdrops the first.- Cards:
"$@"is the row,"$*"the taped strip, unquoted is cut apart. - Save
$1before you shift it away.
