SkillByAIOpen interactive version →

Lesson 12 / 25

Parsing Options with getopts

Build a script interface with flags, usage text and validation.

Professional command-line interfaces

Scripts used by others need a clear interface: short options such as -v (verbose), -n (dry run), -e prod (an option with a value), a usage message on -h or invalid input, and validation of required values. The builtin getopts parses short options in a loop: getopts "vne:h" opt means -v, -n and -h are flags and -e takes an argument (the colon), which arrives in $OPTARG. After the loop, shift $((OPTIND - 1)) removes the parsed options so $@ holds the remaining positional arguments. getopts does not support long options such as --env; for those, write a while loop with case over "$1" and shift, or use GNU getopt (not available by default on macOS). Validate early: missing required options, unknown environments or extra arguments should print usage and exit with status 2. Print usage to stderr for errors and to stdout when the user asked for help.

getopts with validation

Flags, an option with a value and remaining arguments.

#!/usr/bin/env bash
set -euo pipefail

usage() {
    cat <<EOF
usage: ${0##*/} [-v] [-n] -e ENV FILE...
  -e ENV   target environment (dev|staging|prod)
  -n       dry run, change nothing
  -v       verbose output
  -h       show this help
EOF
}

verbose=0 dry_run=0 env=""
while getopts ":vne:h" opt; do
    case $opt in
        v) verbose=1 ;;
        n) dry_run=1 ;;
        e) env=$OPTARG ;;
        h) usage; exit 0 ;;
        :) echo "option -$OPTARG needs a value" >&2; usage >&2; exit 2 ;;
        \?) echo "unknown option -$OPTARG" >&2; usage >&2; exit 2 ;;
    esac
done
shift $(( OPTIND - 1 ))

[[ $env =~ ^(dev|staging|prod)$ ]] || { echo "-e must be dev, staging or prod" >&2; exit 2; }
(( $# > 0 )) || { echo "at least one FILE is required" >&2; exit 2; }

(( verbose )) && echo "env=$env dry_run=$dry_run files=$*"

Make prod require confirmation

For destructive scripts, require an explicit flag or an interactive confirmation when -e prod is used, and support a dry-run mode. Most scripting disasters are someone running the right script against the wrong environment.

Quick check: In `getopts "vne:h" opt`, what does the colon after e mean?

  • -e takes a value, which is placed in $OPTARG
  • -e is optional
  • -e is a long option
  • -e must be the last option
Answer

-e takes a value, which is placed in $OPTARG — A colon after an option letter means that option requires an argument.