Chapter 06Lesson 03~75 minutes

Parsing Short Options with getopts

Bash already provides a parser for conventional short options: `getopts`. It understands option letters and required values without external utilities or re-parsing the command line.

BeginnerCLI designHands-on lab

Learning objectives

By the end of this lesson

  • Define an optstring.
  • Use OPTARG and OPTIND.
  • Handle grouped flags.
  • Report unknown options and missing values cleanly.
  • Shift parsed options before reading operands.

1. getopts parses one option per iteration

verbose=false
environment=staging

while getopts 've:' option; do
  case $option in
    v) verbose=true ;;
    e) environment=$OPTARG ;;
  esac
done

In the optstring ve:, v is a flag and e requires an argument because it is followed by a colon.

2. OPTARG contains the current option argument

output=""

while getopts 'o:' option; do
  case $option in
    o) output=$OPTARG ;;
  esac
done

printf 'output=%s\n' "$output"

3. OPTIND tracks parser progress

while getopts 've:' option; do
  :
done

shift "$((OPTIND - 1))"
printf 'remaining operands=%d\n' "$#"

After the shift, $1 is the first non-option operand remaining for your application.

4. Independent short flags can be grouped

while getopts 'vqn' option; do
  case $option in
    v) verbose=true ;;
    q) quiet=true ;;
    n) dry_run=true ;;
  esac
done

# Users may write -vqn

5. A leading colon gives your script control over errors

while getopts ':ve:' option; do
  case $option in
    v) verbose=true ;;
    e) environment=$OPTARG ;;
    :)
      printf 'option -%s requires an argument\n' "$OPTARG" >&2
      exit 64
      ;;
    \?)
      printf 'unknown option: -%s\n' "$OPTARG" >&2
      exit 64
      ;;
  esac
done

This keeps parser diagnostics consistent with the rest of your CLI.

6. getopts validates grammar, not business meaning

case $environment in
  dev|staging|prod) ;;
  *)
    printf 'invalid environment: %s\n' "$environment" >&2
    exit 65
    ;;
esac

getopts can know that -e requires text, but it cannot know which environment names your tool permits.

7. Parse operands after shifting options

shift "$((OPTIND - 1))"

service=${1:-}
[[ -n $service ]] || {
  printf 'SERVICE required\n' >&2
  exit 64
}

8. Reset OPTIND for an independent second parse

parse_options() {
  local option
  OPTIND=1

  while getopts ':v' option; do
    case $option in
      v) printf 'verbose\n' ;;
    esac
  done
}

parse_options -v
parse_options -v

OPTIND is shell state; reset it when a function performs a new, independent parse in the same process.

9. getopts can parse a function argument vector

parse_deploy_options() {
  local option
  OPTIND=1

  while getopts ':e:v' option "$@"; do
    case $option in
      e) printf 'environment=%s\n' "$OPTARG" ;;
      v) printf 'verbose\n' >&2 ;;
    esac
  done
}

parse_deploy_options -v -e prod

10. getopts is not a general GNU long-option parser

Native Bash getopts targets short options such as -v and -e prod. If you need --environment=prod, use a deliberate manual parser or a stronger CLI framework.

Portability choice

External getopt implementations differ across systems, so do not assume GNU-specific behavior everywhere.

11. Hands-on lab: short-option deployment CLI

mkdir -p "$HOME/devops-academy/bash/chapter06/lesson03"
cd "$HOME/devops-academy/bash/chapter06/lesson03"

cat > deploy-short.sh <<'EOF'
#!/usr/bin/env bash
verbose=false
dry_run=false
environment=staging
replicas=2

while getopts ':vne:r:' option; do
  case $option in
    v) verbose=true ;;
    n) dry_run=true ;;
    e) environment=$OPTARG ;;
    r) replicas=$OPTARG ;;
    :) printf 'option -%s requires a value\n' "$OPTARG" >&2; exit 64 ;;
    \?) printf 'unknown option: -%s\n' "$OPTARG" >&2; exit 64 ;;
  esac
done

shift "$((OPTIND - 1))"
service=${1:-}
[[ -n $service ]] || { printf 'SERVICE required\n' >&2; exit 64; }

case $environment in dev|staging|prod) ;; *) exit 65 ;; esac
[[ $replicas =~ ^[0-9]+$ ]] && (( 10#$replicas >= 1 )) || exit 66

printf 'PLAN service=%s env=%s replicas=%d verbose=%s dry_run=%s\n' \
  "$service" "$environment" "$((10#$replicas))" "$verbose" "$dry_run"
EOF

bash deploy-short.sh -vn -e prod -r 3 api
bash deploy-short.sh -e staging worker
bash deploy-short.sh -x api || true
bash deploy-short.sh -e || true

Verification checklist

12. Knowledge check

Question 1. What does a colon after an option letter mean?

Question 2. What does OPTARG contain?

Question 3. Why shift by OPTIND - 1?

Question 4. Does Bash getopts provide a general long-option parser?

13. Summary

getopts is Bash's built-in short-option parser. Use the optstring to define flags and required values, OPTARG for option data, and OPTIND to locate remaining operands. Your script still owns semantic validation.

14. Further reading

  • GNU Bash Reference Manual — getopts.
  • POSIX getopts utility specification.
  • POSIX Utility Syntax Guidelines.
  • ShellCheck documentation — option parsing.
Next lesson

Designing Usage, Help, and Validation

Continue Chapter 6 by refining the command-line interface and its validation contract.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.