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.