Affectation variable en dehors de la déclaration de cas

8

Dans de nombreuses langues, il est possible d'affecter le résultat d'une instruction case / switch à une variable, plutôt que de répéter l'affectation de variable plusieurs fois dans l'instruction case. Est-il possible de faire quelque chose comme ça dans le shell Bash?

color_code=$(case "$COLOR" in
  (red)    1;;
  (yellow) 2;;
  (green)  3;;
  (blue)   4;;
esac)

(Ou, en passant, dans d'autres coquilles?)

iconoclaste
la source
Vous avez des (s supplémentaires . Sinon, ça va.
HalosGhost

Réponses:

6

La variable=$(...)construction prendra la sortie standard de n'importe quelle commande $(...)et l'affectera à variable. Ainsi, pour être variableassigné comme vous le souhaitez, les valeurs doivent être envoyées à la sortie standard. Cela se fait facilement avec la echocommande:

color_code=$(case "$COLOR" in
  red)    echo 1;;
  yellow) echo 2;;
  green)  echo 3;;
  blue)   echo 4;;
esac)

Cela fonctionnera bashaussi bien sur tous les autres shells POSIX.

Les parens gauche en option

Selon la norme POSIX, la parenthèse gauche dans une caseinstruction est facultative et la suivante fonctionne également:

color_code=$(case "$COLOR" in
  (red)    echo 1;;
  (yellow) echo 2;;
  (green)  echo 3;;
  (blue)   echo 4;;
esac)

Comme Gilles le souligne dans les commentaires, tous les shells n'acceptent pas les deux formes en combinaison avec $(...): pour un tableau de compatibilité incroyablement détaillé, voir "$ ()" substitution de commande vs embarqué ")" .

John1024
la source
Une page que j'ai vérifiée (je ne me souviens pas où elle était) a répertorié l'ouverture (comme facultative. Je pensais que cela pourrait aider à éviter de laisser le )mal interprété comme la fermeture )de l' $(...)expression.
iconoclaste du
@iconoclast Oui. L'ouverture (est facultative: le code fonctionne de la même manière sans ou sans eux. Je les ai laissés de côté uniquement parce que, pour le meilleur ou pour le pire, c'est la tradition. L'élément clé de la solution proposée est l'utilisation de echo.
John1024
1
@iconoclast Les shells plus anciens (pré-POSIX) ne permettaient pas une ouverture (pour les casemodèles, mais certains shells l'ont fait et ont nécessité l'ouverture (quand caseest utilisé dans une substitution de commande. Les coquilles modernes sont bien de toute façon. Voir in-ulm.de/~mascheck/various/cmd-subst
Gilles 'SO- arrête d'être méchant'
1
@Gilles Merci pour cette info. La profondeur de vos connaissances est, comme toujours, impressionnante.
John1024
2

color_code=$(…)assigne la sortie de la commande à la variable color_code, avec les retours à la ligne finaux supprimés. Vous devez donc produire une sortie. Le code que vous avez écrit tente de s'exécuter en 1tant que commande.

Vous pouvez utiliser cet idiome. Notez qu'il color_codesera vide s'il $COLORn'y a aucune des valeurs prises en charge.

color_code=$(case "$COLOR" in
  (red)    echo 1;;
  (yellow) echo 2;;
  (green)  echo 3;;
  (blue)   echo 4;;
esac)

Mais ce n'est pas très idiomatique. Le langage shell est orienté vers de simples combinaisons de commandes simples. Cette grosse substitution de commande est maladroite. La substitution de commande crée un sous-shell, qui est plus lent que la méthode simple:

case "$COLOR" in
  red)    color_code=1;;
  yellow) color_code=2;;
  green)  color_code=3;;
  blue)   color_code=4;;
esac

La principale différence sémantique entre les deux approches est qu'elle $(…)crée un sous-shell, de sorte que toute affectation, sortie, redirection, etc. effectuée à l'intérieur n'a aucun effet à l'extérieur.

Gilles 'SO- arrête d'être méchant'
la source