Bash Tutorial · Bash Scripting · Lesson 21 of 30

Bash Script Arguments and Options

Read positional arguments, validate them, and parse options with getopts.

Create a free account to save this page, take notes and track your progress. Sign in

Positional arguments

$0 is the script name, $1... the arguments, $# the count, and "$@" all of them (quoted, keeps each argument intact). shift drops the first argument.

Options with getopts

A script with getopts
cat > deploy.sh <<'EOF'
#!/usr/bin/env bash
usage() { echo "usage: $0 [-e env] [-n] service..." >&2; exit 2; }
env="staging"; dry_run=false
while getopts ":e:n" opt; do
  case $opt in
    e) env=$OPTARG ;;
    n) dry_run=true ;;
    *) usage ;;
  esac
done
shift $((OPTIND - 1))
(( $# > 0 )) || usage
for svc in "$@"; do echo "deploy $svc to $env (dry run: $dry_run)"; done
EOF
chmod +x deploy.sh
./deploy.sh api web
./deploy.sh -e prod -n api
./deploy.sh -x api 2>&1 || echo "exit status: $?"

Output

deploy api to staging (dry run: false)
deploy web to staging (dry run: false)
deploy api to prod (dry run: true)
usage: ./deploy.sh [-e env] [-n] service...
exit status: 2

Run this on your computer — see “Get Started” for setup.

Print a usage message and exit non-zero on bad input, so callers and CI notice.

Test yourself

What's the difference between "$@" and $*?

  1. None
  2. "$@" keeps each argument separate; $* joins and re-splits them
  3. $* includes $0
  4. "$@" only works in functions
Show answer

Answer: "$@" keeps each argument separate; $* joins and re-splits them

Was this page helpful?