1

Is there any way to retrieve a list of the options in a case statement? For example if I have this code:

tool=$1

case ${tool} in 
     brdf)
        # Do stuff
        ;;
     drift)
        # Do other stuff
        ;;
     *)
        echo "ERROR: I don't know this tool. Valid options are: brdf, drift"
        exit 1
        ;;
esac

This is easy to read, but the error message could easily get out of date when adding/removing tools from the list as I need to remember to change the names there too.

The repetition could be avoided using an array something like this:

tool=$1

validtools=(brdf drift)

case ${tool} in
     ${validtools[0]})
           # Do stuff
           ;;
     ${validtools[1]})
           # Do other stuff
           ;;
     *)
           echo "ERROR: I don't know this tool. Valid options are: ${validtools[@]}"
           exit 1
           ;;
esac

But that is pretty horrible to read, and in any case would be even worse to maintain with the hardcoded array indices.

Is there a good way of doing this, perhaps some variable or command that retrieves a list of the available options, or do I just have to remember to update the error message when I add a new option?

codeforester
  • 39,467
  • 16
  • 112
  • 140
ammonite
  • 206
  • 2
  • 12

1 Answers1

5

The most used way is as your 1st example. See all init scripts in linux.

And it is for reason, because you can use constructions like:

case "$a" in
    arg1|arg2|arg3) ... ;;
    brg1|brg2) ... ;; 
    brg2) ... ;;
esac

and would be hard contstuct automatically the right usage message with the all possible variants.

And here is the shopt -s extglob too, what allows you to use extended pattern matching in the case statemens. For examples see this answer: https://stackoverflow.com/a/4555979/632407

But if you want use arrays, try to use associative array, what add a bit of readability. (But it is terrible anyway) :) Like the next:

declare -A arg

initargs() { for a in "$@"; do arg[$a]="$a"; done; }

initargs brd lbrs ubrs

for myarg 
do
    case "$myarg" in
        ${arg[brd]}) echo "brd";;
        ${arg[ubrs]}) echo "ubrs";;
        ${arg[lbrs]}) echo "lbrs";;
        *) echo "Unknown arg =$myarg=. Known are: ${arg[@]}" ;;
    esac
done

So the allowed args are: "brd" "lbrs" "ubrs" and the script for the next input

$ bash argtest ubrs badarg brd

produces:

ubrs
Unknown arg =badarg=. Known are: lbrs ubrs brd
brd
Community
  • 1
  • 1
clt60
  • 62,119
  • 17
  • 107
  • 194
  • `;&` probably is a typo? – konsolebox Jul 10 '14 at 12:32
  • 1
    @konsolebox not really.. ;) it is bash 4.0 extension.. ;) (but not in POSIX) = youre right, it confusing - so re-edited my answer. – clt60 Jul 10 '14 at 12:33
  • 1
    I see. I never knew the extension. It's pretty good for Bash scripts when 3.* finally gets truly obsolete. No seriously it's helpful and I might consider using them someday. – konsolebox Jul 10 '14 at 12:37
  • Thanks, I will leave it as it is then. Shame, I was hoping there might be a secret $CASEOPTS variable or something ;) – ammonite Jul 11 '14 at 08:23