Option Parsing with getopts
Add professional -f, -v, -o style flags to your scripts. The built-in getopts handles single-character options, optional values, and unknown flag errors.
Professional command-line tools accept flags like -v for verbose or -o output.txt. Bash's built-in getopts implements the POSIX standard for parsing single-character options, including options that take values. It handles edge cases (combined flags like -vf file, unknown flags, missing arguments) automatically.
getopts Syntax
while getopts "optstring" opt; do
case "$opt" in
# handle each option
esac
done
shift $(( OPTIND - 1 )) # remove processed options from $@
# remaining "$@" are the non-option argumentsThe optstring lists the accepted option letters:
- Plain letter (
v) → flag with no argument - Letter followed by
:(o:) → option that requires an argument (stored in$OPTARG) - Leading
:(:vo:) → silent error mode (you handle unknown options)
Complete Example
#!/usr/bin/env bash
verbose=false
output_dir="./backups"
max_files=10
function usage {
cat >&2 <<-EOF
Usage: $0 [-v] [-o DIR] [-n COUNT] <source>
Options:
-v Verbose output
-o DIR Output directory (default: ./backups)
-n COUNT Max files to keep (default: 10)
-h Show this help
EOF
exit 1
}
# Parse options
while getopts ":vo:n:h" opt; do
case "$opt" in
v) verbose=true ;;
o) output_dir="$OPTARG" ;;
n) max_files="$OPTARG" ;;
h) usage ;;
:) echo "Option -$OPTARG requires an argument" >&2; usage ;;
?) echo "Unknown option: -$OPTARG" >&2; usage ;;
esac
done
# Remove parsed options, leaving positional arguments
shift $(( OPTIND - 1 ))
# Now $1 is the first non-option argument
if [[ $# -eq 0 ]]; then
echo "ERROR: source directory required" >&2
usage
fi
source="$1"
$verbose && echo "Backing up: $source → $output_dir (max: $max_files)"Key Variables
getopts built-in variables
| Variable | Meaning |
|---|---|
$OPTARG | Value of the argument for options that take one |
$OPTIND | Index of the next argument to process (used with shift) |
$opt | The current option character (the variable name you choose) |
? | Unknown option |
: | Option missing its required argument |
Limitations — When to Use Alternatives
getopts limitations
getopts only handles single-character options (-v, -o). It does NOT support:
- Long options (
--verbose,--output) - Optional arguments to options
For long options, use getopt (the external command, not the builtin) or parse manually with a while loop pattern.
# Manual long option parsing (for long flags)
while [[ $# -gt 0 ]]; do
case "$1" in
--verbose|-v) verbose=true; shift ;;
--output|-o) output_dir="$2"; shift 2 ;;
--help|-h) usage ;;
--) shift; break ;; # end of options
-*) echo "Unknown: $1" >&2; usage ;;
*) break ;; # first non-option arg
esac
doneAfter `while getopts "vo:" opt; do ... done`, what does `shift $((OPTIND - 1))` accomplish?
Write a script greet.sh that:
- Accepts
-n name(name to greet, default "World") - Accepts
-c count(how many times to greet, default 1) - Accepts
-u(uppercase output) - Prints "Hello, NAME!" repeated COUNT times, optionally uppercased
Example: ./greet.sh -n Alice -c 3 -u → "HELLO, ALICE!" three times