Snažím se použít proměnnou skládající se z různých řetězců oddělených |
jako case
výrokový test. Například:
string=""foo"|"bar""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Chci umět psát foo
nebo bar
a spusťte první část case
prohlášení. Nicméně oba foo
a bar
vezmi mě na druhou:
$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!
Pomocí "$string"
místo $string
nedělá žádný rozdíl. Ani použití string="foo|bar"
.
Vím, že to mohu udělat takto:
case $choice in
"foo"|"bar")
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Napadají mě různá řešení, ale rád bych věděl, zda je možné použít proměnnou jako case
stav v bash. Je to možné, a pokud ano, jak?
Přijatá odpověď:
Bash manuál uvádí:
velká a malá písmena v seznamu [ [(] vzor [ | vzor ] … );; ] … esac
Každý zkoumaný vzor je rozšířen pomocí rozšiřování vlnovky, rozšiřování parametrů a proměnných, aritmetické substituce, substituce příkazů a substituce procesu.
Žádné «rozšíření názvu cesty»
Tedy:vzor NENÍ rozšířen pomocí «Rozšíření názvu cesty».
Proto:vzor NEMŮŽE obsahovat „|“ uvnitř. Pouze:dva vzory lze spojit pomocí „|“.
Toto funguje:
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
Pomocí « Extended Globbing »
Nicméně word
odpovídá pattern
pomocí pravidel « Expanze názvů ».
A « Rozšířené globování » zde, zde a zde umožňuje použití alternujících (“|”) vzorů.
Toto také funguje:
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
Obsah řetězce
Další testovací skript ukazuje, že vzor odpovídá všem řádkům, které obsahují buď foo
nebo bar
kdekoli je '*$(foo|bar)*'
nebo dvě proměnné $s1=*foo*
a $s2=*bar*
Testovací skript:
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 "%sn" "$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_