Sagar.BlogArticle
All posts
All posts
Bash

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.

January 25, 20267 min read
BashgetoptsCLIScripting

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 arguments

The 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

backup.sh
#!/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

VariableMeaning
$OPTARGValue of the argument for options that take one
$OPTINDIndex of the next argument to process (used with shift)
$optThe 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
done
Quick Check

After `while getopts "vo:" opt; do ... done`, what does `shift $((OPTIND - 1))` accomplish?

Exercise

Write a script greet.sh that:

  1. Accepts -n name (name to greet, default "World")
  2. Accepts -c count (how many times to greet, default 1)
  3. Accepts -u (uppercase output)
  4. Prints "Hello, NAME!" repeated COUNT times, optionally uppercased

Example: ./greet.sh -n Alice -c 3 -u → "HELLO, ALICE!" three times