How can I use a variable as a case condition?
The bash manual states:
case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
Each pattern examined is expanded using tilde expansion, parameter and variable expansion, arithmetic substitution, command substitution, and process substitution.
No «Pathname expansion»
Thus: a pattern is NOT expanded with «Pathname expansion».
Therefore: a pattern could NOT contain "|" inside. Only: two patterns could be joined with the "|".
This works:
s1="foo"; s2="bar" # or even s1="*foo*"; s2="*bar*"
read choice
case $choice in
$s1|$s2 ) echo "Two val choice $choice"; ;; # not "$s1"|"$s2"
* ) echo "A Bad choice! $choice"; ;;
esac
Using « Extended Globbing »
However, word
is matched with pattern
using « Pathname Expansion » rules.
And « Extended Globbing » here, here and, here allows the use of alternating ("|") patterns.
This also work:
shopt -s extglob
string='@(foo|bar)'
read choice
case $choice in
$string ) printf 'String choice %-20s' "$choice"; ;;&
$s1|$s2 ) printf 'Two val choice %-20s' "$choice"; ;;
*) printf 'A Bad choice! %-20s' "$choice"; ;;
esac
echo
String content
The next test script shows that the pattern that match all lines that contain either foo
or bar
anywhere is '*$(foo|bar)*'
or the two variables $s1=*foo*
and $s2=*bar*
Testing script:
shopt -s extglob # comment out this line to test unset extglob.
shopt -p extglob
s1="*foo*"; s2="*bar*"
string="*foo*"
string="*foo*|*bar*"
string='@(*foo*|*bar)'
string='*@(foo|bar)*'
printf "%s\n" "$string"
while IFS= read -r choice; do
case $choice in
"$s1"|"$s2" ) printf 'A first choice %-20s' "$choice"; ;;&
$string ) printf 'String choice %-20s' "$choice"; ;;&
$s1|$s2 ) printf 'Two val choice %-20s' "$choice"; ;;
*) printf 'A Bad choice! %-20s' "$choice"; ;;
esac
echo
done <<-\_several_strings_
f
b
foo
bar
*foo*
*foo*|*bar*
\"foo\"
"foo"
afooline
onebarvalue
now foo with spaces
_several_strings_
You can use the extglob
option:
shopt -s extglob
string='@(foo|bar)'
You need two variables for case
because the or |
pipe is parsed before the patterns are expanded.
v1=foo v2=bar
case foo in ("$v1"|"$v2") echo foo; esac
foo
Shell patterns in variables are handled differently when quoted or unquoted as well:
q=?
case a in
("$q") echo question mark;;
($q) echo not a question mark
esac
not a question mark