5

I want to know if there is any way to case on multiple variables at once, like this:

#/bin/bash
arr1=(1 2)
arr2=(3 4)
foo=1
bar=2

case $foo && $bar in
    ${arr1[@]})
        echo "variables equal array 1!";;
    ${arr2[@]})
        echo "variables equal array 2!";;
    *)
        echo "variables do not exactly equal any array!";;
esac

I don't want to put $foo and $bar in an array themselves, but I can if I absolutely have to.

3 Answers 3

6

Assuming IFS hasn’t been changed from its default value:

case "$foo $bar" in
"${arr1[*]}") echo "variables equal array 1!" ;;
"${arr2[*]}") echo "variables equal array 2!" ;;
*) echo "variables do not exactly equal any array!" ;;
esac

This is only reliable if the separator (a space) isn’t present in the individual values stored in each array.

2
  • 2
    And like always(?) when one tries to represent an array as a single string in a straightforward way, some restriction on possible values is needed. Here foo=a; bar='b c' gives the same string as foo='a b'; bar=c. Jul 3 at 22:09
  • This also requires the variables to be in the same order as the array elements.
    – Barmar
    Jul 4 at 14:10
3

First off, I wouldn't worry about array variables.

Second, you can use any separator you like, provided it doesn't appear in your variables. I often use "/".

Something like:

case "$foo"/"$bar" in
(1/2) echo variables equal to first pattern\! ;;
(3/4) echo variables equal to second pattern\! ;;
(*) echo variables match no pattern. ;;
esac

This also then allows you to write wildcard entries fairly easily, like a line reading:

(1??/2??) echo variables are similar to the first pattern, but bigger\! ;;

Remember that the order of the patterns matters (first match wins), and that you want a separator that does not appear in your values.

Also, if you make your first pattern something like (*/*/*) you can test for your separator appearing in your values.

1

You could compare the output of typeset -p to do array equality comparison:

case $(a=("$foo" "$bar"); typeset -p a) in
  ("$(a=("${arr1[@]}"); typeset -p a)") ...;;
  ("$(a=("${arr2[@]}"); typeset -p a)") ...;;
esac

With zsh, you can join the elements after applying quoting to produce a deterministic string representation of the arrays which you can then compare as strings without having to run typeset -p in a subshell:

case "${(q)foo} ${(q)bar}" in
  (${(j[ ])${(q)arr1}}) ...;;
  (${(j[ ])${(q)arr2}}) ...;;
esac

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.