Skip to content
Latchkey

bash getopts pitfalls in CI

getopts parses single-dash short options from a fixed optstring. Common CI failures come from not resetting OPTIND when parsing twice, forgetting the leading : for silent error handling, expecting long --options (getopts does not support them), or shifting the wrong count so positional args are lost.

What this error means

Flags are ignored, "illegal option" is printed for valid flags on a second parse, or positional arguments after the options are missing. Long options like --verbose are treated as a single - cluster.

bash
while getopts "ab:" opt; do   # no leading colon: getopts prints its own errors
  case "$opt" in
    a) all=1 ;;
    b) name="$OPTARG" ;;
  esac
done
# parsing again later without: OPTIND=1  -> options are skipped

Common causes

OPTIND not reset between parses

getopts uses the global OPTIND to track position. Calling a parse loop a second time without resetting OPTIND=1 continues from the old index and skips options.

Missing leading colon and long-option assumptions

Without a leading : in the optstring, getopts prints its own error messages instead of letting you handle ? and :. And getopts only handles short options; --long forms are not parsed.

How to fix it

Use a leading colon and handle : and ?

Put : first in the optstring for silent errors, then handle a missing argument (:) and an unknown option (?) yourself.

bash
while getopts ":ab:" opt; do
  case "$opt" in
    a) all=1 ;;
    b) name="$OPTARG" ;;
    :) echo "-$OPTARG needs a value" >&2; exit 1 ;;
    \?) echo "unknown option -$OPTARG" >&2; exit 1 ;;
  esac
done
shift $((OPTIND - 1))

Reset OPTIND before reparsing

When a function or loop parses options more than once, set OPTIND=1 first so parsing starts fresh.

bash
OPTIND=1
while getopts ":v" opt; do ...; done

How to prevent it

  • Always shift $((OPTIND - 1)) after the loop to reach positionals.
  • Reset OPTIND=1 before each independent parse.
  • Use a helper like getopt (GNU) if you need long options.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →