Sto cercando di utilizzare una variabile composta da stringhe diverse separate da un | come case prova di affermazione. Ad esempio:
string=""foo"|"bar""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Voglio poter digitare foo o bar ed eseguire la prima parte del case dichiarazione. Tuttavia, entrambi foo e bar portami al secondo:
$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!
Usando "$string" invece di $string non fa differenza. Neanche l'uso di string="foo|bar" .
So che posso farlo in questo modo:
case $choice in
"foo"|"bar")
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Mi vengono in mente varie soluzioni alternative, ma vorrei sapere se è possibile utilizzare una variabile come case condizione in bash. È possibile e, se sì, come?
Risposta accettata:
Il manuale di bash afferma:
parola maiuscola nell'elenco [[(] modello [ | modello ] … );; ] … esac
Ciascun modello esaminato viene espanso utilizzando l'espansione della tilde, l'espansione di parametri e variabili, la sostituzione aritmetica, la sostituzione di comandi e la sostituzione di processi.
Nessuna «Espansione del percorso»
Pertanto:un modello NON viene espanso con «Espansione del nome del percorso».
Pertanto:un pattern NON può contenere “|” dentro. Solo:due pattern possono essere uniti con “|”.
Funziona:
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
Utilizzo di «Globbing esteso»
Tuttavia, word è abbinato a pattern usando le regole di «Espansione del nome».
E «Globbing esteso» qui, qui e qui consente l'uso di pattern alternati ("|").
Funziona anche questo:
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
Contenuto della stringa
Lo script di test successivo mostra che il modello corrisponde a tutte le righe che contengono foo o bar ovunque è '*$(foo|bar)*' oppure le due variabili $s1=*foo* e $s2=*bar*
Script di prova:
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_