How to pass arguments to a Bash script

Pass arguments to a Bash script using $1..$9, $@, getopts for flags, and shift for processing. A practical guide with defaults and validation patterns.

Tldr

Inside the script, positional arguments are $1, $2, $3 (up to $9 unbraced; ${10} after that). $@ is all of them as separate words, $# is the count. For named flags (`--verbose`), use getopts (POSIX, single-letter) or a manual while/case loop (long options).

Intro

Passing arguments to a Bash script is one of those things every shell programmer half-knows. Here is the full picture: positional access, validation, defaults, and named flags.

Steps

Name

Access positional arguments

Text

Bash exposes arguments as numbered variables. Always quote them — unquoted $1 is split on whitespace.

Name

Validate the count

Text

Bail out early with a usage message and a non-zero exit code if required arguments are missing.

Name

Provide defaults

Text

Use parameter expansion to default optional arguments. ${1:-value} expands to "value" when $1 is unset or empty.

Name

Loop over all arguments

Text

Use "$@" — always quoted — to iterate over arguments while preserving spaces and special characters in each one.

Name

Parse named flags with getopts

Text

getopts handles single-letter flags (-v, -o file). It is POSIX and built into Bash. Long options (--verbose) require a manual loop or external getopt.

Name

Parse long options manually

Text

For --verbose / --output=foo style flags, hand-roll a while/case loop. It is more code than getopts but works on every shell.

Faq

Q

What is the difference between $@ and $*?

A

When quoted, "$@" expands to each argument as a separate word — "arg one" stays one word. "$*" joins all arguments into a single word separated by the first character of IFS. Almost always use "$@".

Q

Why $10 not working?

A

Bash parses $10 as $1 followed by literal 0. For arguments past 9, brace it: ${10}, ${11}, etc.

Q

How do I pass arrays?

A

You cannot pass an array directly. Pass it as separate arguments and reconstruct with `arr=("$@")` inside the function, or export it as a string and split.