How to parse command-line flags in Bash with getopts
Parse short command-line flags in Bash using the getopts builtin. Covers required arguments, optional flags, usage errors, and combining with long options.
Tldr
Use the `getopts` builtin in a `while getopts ":a:bh" opt; do case $opt in ... esac; done` loop to parse short flags like -a value, -b, and -h. Colons in the option string mark flags that require an argument; a leading colon enables silent error handling so you can report custom usage messages.
Intro
getopts is the standard, POSIX-compatible way to parse short command-line options in shell scripts, handling combined flags (-ab), required arguments, and unknown-option errors without any external dependency.
Steps
Name
Set up the getopts loop and option string
Text
The option string lists valid flags; a colon after a letter means it takes an argument. A leading colon suppresses getopts' default error messages so you control them yourself.
Name
Shift past the parsed options
Text
After the loop, OPTIND holds the index of the first non-option argument. shift $((OPTIND - 1)) moves the remaining positional arguments into $1, $2, ...
Name
Handle a flag with a required argument
Text
When the option string has a colon after the letter (like n:), getopts automatically captures the next word as $OPTARG.
Name
Handle boolean flags
Text
Flags without a following colon (like v and h above) take no argument; just set a variable or run logic directly in the case branch.
Name
Support combined short flags
Text
getopts automatically understands combined boolean flags like -vh as -v -h, which is one of its advantages over manual $1/$2 parsing.
Faq
Q
Does getopts support long options like --verbose?
A
No, the getopts builtin only supports single-character short options. For long options, use GNU `getopt` (a separate external command, not the builtin) or write manual parsing with a case statement over "$1" in a while loop.
Q
Why do I need OPTIND and shift after the loop?
A
getopts does not remove parsed options from the argument list itself; it only advances OPTIND. `shift $((OPTIND - 1))` is the standard idiom to drop the consumed options and leave true positional arguments in $1, $2, etc.
Q
What does the leading colon in the option string do?
A
A leading colon (e.g. ":n:vh") puts getopts into silent error-reporting mode: instead of printing its own error and setting $opt to "?", it sets $opt to ":" for missing arguments and "?" for unknown options while leaving $OPTARG set, letting your script print custom error messages.