Every argument passed to a script becomes a numbered variable inside it.
#!/bin/bash
echo "script: $0" # script name (the path used to invoke it)
echo "first: $1"
echo "second: $2"
echo "count: $#"
echo "all: $@"
Run it:
./greet.sh alice bob charlie
# script: ./greet.sh
# first: alice
# second: bob
# count: 3
# all: alice bob charlie
Key pieces:
$0 is the script name.$1 through $9 are the first nine arguments. For the 10th and beyond you need braces: ${10}, ${11}.$# is the count of arguments.$@ and $* are both "all arguments" but behave differently when quoted.Two flavors of "all arguments":
"$@" # each argument as a separate word: "$1" "$2" "$3" ...
"$*" # all arguments joined into one string: "$1 $2 $3"
Almost always you want "$@". It preserves argument boundaries,
so an argument containing spaces stays as one argument.
./deploy.sh "monthly report.pdf" backup.tgz
# inside deploy.sh:
for f in "$@"; do echo "$f"; done
# monthly report.pdf
# backup.tgz
for f in "$*"; do echo "$f"; done
# monthly report.pdf backup.tgz (one line, wrong for iteration)
Rule: use "$@" (with the double quotes) any time you iterate
or forward arguments.
shift drops $1 and shifts everything down. $2 becomes
$1, $3 becomes $2, and $# decreases by one.
first=$1
shift # now $1 is what was $2
second=$1
Useful when you want to consume a "leading" argument and hand the rest off to another command:
action=$1
shift
case $action in
deploy) ./deploy.sh "$@" ;;
rollback) ./rollback.sh "$@" ;;
esac
for arg in "$@"; do
echo "processing $arg"
done
Each iteration binds arg to one argument. Handles spaces
correctly because of "$@".