3

I have a bash script which accepts three command line arguments, e.g script is executed like this: script -c <value> -h <value> -w <value>. I would like to ensure that:

  • order of arguments is not important
  • if argument does not have a value, then error message is printed
  • if any of the arguments are missing, then error message is printed
  • if there are unknown arguments, then error message is printed

I accomplished this with following case statements:

#!/bin/bash

while :; do
  case "$1" in
    -h)
      [[ x${2%%-*} != x ]] || { echo "Value for "$1" missing!"; exit 1; }
      host="$2"
      shift 2
    ;;
    -w)
      [[ x${2%%-*} != x ]] || { echo "Value for "$1" missing!"; exit 1; }
      warning="$2"
      shift 2
    ;;
    -c)
      [[ x${2%%-*} != x ]] || { echo "Value for "$1" missing!"; exit 1; }
      critical="$2"
      shift 2
    ;;
    "")
      [[ $host && $warning && $critical ]] || { echo "One of the arguments is missing!"; exit 1; }
      break
    ;;
    *)
      echo "Unknow option"
      exit 1
    ;;
  esac
done

However, maybe case itself has some advanced options which could avoid all those [[ ]] tests? Or maybe I should use another method altogether for processing command line arguments if I want to make sure that corner cases described above are also covered?

Martin
  • 957
  • 7
  • 25
  • 38

1 Answers1

0

You should ideally use the getopts builtin for this, though there are other ways as well. Getopts is the most portable and legible option, handling all of your "corner cases" pretty much automatically.

while getopts c:h:w: arg; do
  case $arg in
    ( c )  critical="$OPTARG" ;;
    ( h )  host="$OPTARG" ;;
    ( w )  warning="$OPTARG" ;;
    ( \? ) exit 2 ;;
  esac
done
shift $((OPTIND-1))

if [ -z "$critical" ] || [ -z "$host" ] || [ -z "$warning" ]; then
  echo "One of the arguments is missing!"
  exit 1
fi

Each option is followed by a colon, which indicates it has a mandatory argument. If you have a flag that does not use an argument, do not follow the option with a colon. POSIX getopts does not support options with optional arguments.

See also my answer to this question about supporting long options, which merely keys on the - option whose argument is parsed by a nested case switch. Long options implemented in this manner can actually support optional arguments.

 

I'm a big fan of overloading -h for help. Assuming you have a help function, put this before the getopts loop:

# when the sole argument is -h, provide help
if [ "$*" = "-h" ]; then
  help
  exit 0
fi
Adam Katz
  • 14,455
  • 5
  • 68
  • 83