J'essaie d'utiliser une variable composée de différentes chaînes séparées par un |
comme case
test de déclaration. Par exemple:
string="\"foo\"|\"bar\""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Je veux pouvoir taper foo
ou bar
et exécuter la première partie de l' case
instruction. Cependant, les deux foo
et bar
amenez-moi au second:
$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!
Utiliser "$string"
au lieu de $string
ne fait aucune différence. L'emploi non plus string="foo|bar"
.
Je sais que je peux le faire de cette façon:
case $choice in
"foo"|"bar")
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Je peux penser à différentes solutions de contournement, mais je voudrais savoir s'il est possible d'utiliser une variable comme case
condition dans bash. Est-ce possible et, si oui, comment?
bash
shell-script
case
terdon
la source
la source
eval
, en évitant $ choice, les parens, l'astérisque, les points-virgules et les nouvelles lignes. Moche, mais ça "marche".read
bit m'a arrêté. à mon avis, la validation des entrées utilisateur, ce qui semble être le cas, lescase
modèles ne devraient pas être en haut de la liste d'évaluation et devraient plutôt être élagués vers le*
modèle par défaut de sorte que les seuls résultats qui y parviennent soient garantis acceptables. encore, parce que le problème est l'ordre d'analyse / d'extension, alors une deuxième évaluation pourrait être ce qui est demandé.Réponses:
Le manuel bash déclare:
Pas d '«extension de nom de chemin»
Ainsi: un motif n'est PAS étendu avec «Expansion de nom de chemin».
Par conséquent: un modèle ne peut PAS contenir "|" à l'intérieur. Seulement: deux modèles peuvent être joints avec le "|".
Cela marche:
Utilisation de «Extended Globbing»
Cependant, cela
word
correspond à l'pattern
utilisation des règles «Expansion de noms de chemins».Et «Extended Globbing» ici , ici et, ici permet l'utilisation de motifs alternés ("|").
Cela fonctionne également:
Contenu de chaîne
Le script de test suivant montre que le modèle qui correspond à toutes les lignes qui contiennent soit
foo
oubar
n'importe où est'*$(foo|bar)*'
ou les deux variables$s1=*foo*
et$s2=*bar*
Script de test:
la source
Vous pouvez utiliser l'
extglob
option:la source
@(foo|bar)
spécial par rapport àfoo|bar
? Les deux sont des modèles valides qui fonctionnent de la même manière lorsqu'ils sont saisis littéralement.|
ne fait pas partie du modèle dansfoo|bar
, il fait partie de la syntaxe de l'case
instruction pour autoriser plusieurs modèles dans une clause.|
fait partie du modèle étendu, cependant.Vous avez besoin de deux variables
case
car le ou le|
tube est analysé avant que les modèles ne soient développés.Les modèles de shell dans les variables sont traités différemment lorsqu'ils sont entre guillemets ou non:
la source
Si vous voulez une solution de contournement compatible avec les tirets, vous pouvez écrire:
Explication: awk est utilisé pour diviser la "chaîne" et tester chaque partie séparément. Si "choix" correspond à la partie p [i] actuellement testée, la commande awk se terminera par "exit" à la ligne 11. Pour le test même, le "case" du shell est utilisé (dans un appel "system") , comme l'a demandé terdon. Cela conserve la possibilité de modifier la «chaîne» test par exemple en «foo * | bar» afin de faire correspondre également «foooo» («modèle de recherche»), comme le permet la «casse» du shell. Si vous préférez plutôt les expressions régulières, vous pouvez omettre l'appel "system" et utiliser à la place "~" ou "match" d'awk.
la source