Getopts

Here's a useful pattern for collecting command line options in a script:

ERROR="Bad usage, see ${0##*/} -h"

read -r -d "" USAGE <<EOF
Short description

Usage: ${0##*/} [-fh]
  -f ARG      Do something
  -h          Show usage

Example:
  ${0##*/} -f my-arg

EOF

if [ "$1" = "--help" ]; then
  echo "$USAGE" && exit 0
fi

while getopts f:h opt; do
  case $opt in
    f) VAR=$OPTARG                         ;;
    h) echo "$USAGE" && exit 0             ;;
    *) echo "$ERROR" && exit 1             ;;
  esac
done

I like to combine this with a check for superfluous positional arguemnts:

POS_ARG=${*:$OPTIND:1}

OTHER_ARGS=${*:$OPTIND+1}

if [ -n "$OTHER_ARGS" ]; then
  echo "ERROR: Unprocessed positional arguments: $OTHER_ARGS"
  exit 1
fi

If you only expect a specific number of positional arguments, this is a good safety measure, because it reduces the risk of missing important options. Because getopts will stop processing options as soon as it hits a positional argument, in a case like this:

$ ./my_script.sh -f f_arg pos_arg -h

the -h flag will be ignored. Imagine it being a dry-run toggle, for example - better to quit than to miss that.

Last updated