Linux Basics: Parse Bash Options with getopts
Give small scripts clear flags without manually shifting every argument. Start with short options, then handle input errors and remaining filenames.
These examples were tested on Linux with GNU Bash 5.2.37. Use Bash rather than sh. No packages or administrator access are needed.
Prepare a scratch directory
You need Bash, a text editor, and the mktemp, rm, and rmdir utilities. Keep using the same terminal. Save each named source file in this scratch directory before running its command. Calling bash explicitly avoids changing executable permissions.
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 11. Read a flag and an option value
Save this as options-name.sh:
#!/usr/bin/env bash
verbose=no
name=world
while getopts ':vn:' option; do
case "$option" in
v) verbose=yes ;;
n) name=$OPTARG ;;
:) printf 'Missing value: -%s\n' "$OPTARG" >&2; exit 2 ;;
\?) printf 'Unknown option: -%s\n' "$OPTARG" >&2; exit 2 ;;
esac
done
printf 'Hello, %s; verbose=%s\n' "$name" "$verbose"Run it:
bash options-name.sh -v -n "Ada Lovelace"Output:
Hello, Ada Lovelace; verbose=yesThe colon after n requires a value. OPTARG holds that value. Keep values quoted when passing them to other commands.
2. Report a missing value
Save this as options-errors.sh:
#!/usr/bin/env bash
while getopts ':o:' option; do
case "$option" in
o) printf 'Output: %s\n' "$OPTARG" ;;
:) printf 'Missing value: -%s\n' "$OPTARG" >&2; exit 2 ;;
\?) printf 'Unknown option: -%s\n' "$OPTARG" >&2; exit 2 ;;
esac
doneRun it:
bash options-errors.sh -o
printf "Status: %s\n" "$?"Output:
Missing value: -o
Status: 2A leading colon enables silent error reporting so your script can supply its own diagnostics. This example intentionally exits with status 2. Save or print $? immediately.
3. Keep filenames after the options
Save this as options-operands.sh:
#!/usr/bin/env bash
quiet=no
while getopts ':q' option; do
case "$option" in
q) quiet=yes ;;
*) printf 'Unknown option: -%s\n' "$OPTARG" >&2; exit 2 ;;
esac
done
shift "$((OPTIND - 1))"
printf 'Quiet: %s\n' "$quiet"
for file in "$@"; do
printf 'File: %s\n' "$file"
doneRun it:
bash options-operands.sh -q -- -report.txt "draft notes.txt"Output:
Quiet: yes
File: -report.txt
File: draft notes.txtThe shift removes consumed options; -- ends option parsing. Put options before operands. getopts handles short options, not general GNU long options. Reset OPTIND=1 before parsing a fresh argument list in the same shell.
Clean up
In the same terminal, remove only the example files, return to your original directory, and remove the empty scratch directory:
rm -- options-name.sh options-errors.sh options-operands.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirReference
See the GNU Bash manual: Bourne Shell Builtins for the relevant shell behavior. The installed Bash help command also documents these builtins.
Acknowledgements
This post was created with assistance from AI.