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_