Parsing Options with getopts
Prerequisites: Script arguments, The case statement
Real command-line tools take options — -v for verbose, -o file
for output. getopts parses them reliably.
Example
cat > resize.sh <<'EOF'
#!/usr/bin/env bash
usage() { echo "Usage: $0 [-v] [-w width] file..." >&2; exit 2; }
verbose=false
width=800
while getopts ":vw:h" opt; do
case "$opt" in
v) verbose=true ;;
w) width=$OPTARG ;;
h) usage ;;
:) echo "Option -$OPTARG needs a value" >&2; usage ;;
\?) echo "Unknown option -$OPTARG" >&2; usage ;;
esac
done
shift $(( OPTIND - 1 ))
(( $# > 0 )) || usage
for file in "$@"; do
$verbose && echo "Resizing $file to ${width}px"
done
echo "Done: $# file(s)"
EOF
bash resize.sh -v -w 1200 a.jpg "b c.jpg"
bash resize.sh a.jpg
bash resize.sh -x a.jpg
echo "exit code: $?"
Resizing a.jpg to 1200px
Resizing b c.jpg to 1200px
Done: 2 file(s)
Done: 1 file(s)
Unknown option -x
Usage: resize.sh [-v] [-w width] file...
exit code: 2
How it works:
":vw:h"lists the options. A colon after a letter (w:) means it takes a value, available in$OPTARG. The leading colon enables custom error handling (the:and?cases).- The loop runs once per option;
casehandles each one. shift $(( OPTIND - 1 ))removes the parsed options, leaving just the remaining arguments (the files) in"$@".- Short options can be combined:
-vw 1200works too.
Long options
getopts only supports short options. For long options like --width,
loop over the arguments yourself:
parse() {
local width=800 dry_run=false
while (( $# > 0 )); do
case "$1" in
--width) width=$2; shift 2 ;;
--width=*) width=${1#*=}; shift ;;
--dry-run) dry_run=true; shift ;;
--) shift; break ;;
-*) echo "Unknown option: $1" >&2; return 2 ;;
*) break ;;
esac
done
echo "width=$width dry_run=$dry_run files=$*"
}
parse --width 640 --dry-run photo.jpg
parse --width=1024 a.jpg b.jpg
width=640 dry_run=true files=photo.jpg
width=1024 dry_run=false files=a.jpg b.jpg
-- conventionally marks the end of options, so a file named -report
isn't mistaken for an option.
Always provide --help
A usage message listing every option, with an example, turns a personal script into a tool others can use.