289 votes

Opérateurs logiques simples en Bash

J'ai quelques variables et je veux vérifier la condition suivante (écrite en mots, puis ma tentative ratée de scripting bash) :

if varA EQUALS 1 AND ( varB EQUALS "t1" OR varB EQUALS "t2" ) then 

do something

done.

Et dans ma tentative ratée, je suis arrivé avec :

if (($varA == 1)) && ( (($varB == "t1")) || (($varC == "t2")) ); 
  then
    scale=0.05
  fi

760voto

Gilles Points 37537

Ce que vous avez écrit fonctionne presque (cela fonctionnerait si toutes les variables étaient des nombres), mais ce n'est pas du tout une manière idiomatique.

  • (…) Les parenthèses indiquent une Sous-coque . Ce qui se trouve à l'intérieur n'est pas une expression comme dans beaucoup d'autres langues. Il s'agit d'une liste de commandes (comme à l'extérieur des parenthèses). Ces commandes sont exécutées dans un sous-processus distinct, de sorte que toute redirection, affectation, etc. effectuée à l'intérieur des parenthèses n'a aucun effet à l'extérieur de celles-ci.
    • Avec un signe de dollar en tête, $(…) est un substitution de commande il y a une commande à l'intérieur des parenthèses, et la sortie de la commande est utilisée comme partie de la ligne de commande (après des expansions supplémentaires, sauf si la substitution est entre guillemets doubles, mais c'est une autre histoire ).
  • { … } Les accolades sont comme les parenthèses en ce sens qu'elles regroupent les commandes, mais elles n'influencent que l'analyse syntaxique, pas le regroupement. Le programme x=2; { x=4; }; echo $x imprime 4, alors que x=2; (x=4); echo $x imprime 2. (Les accolades doivent être entourées d'espaces et d'un point-virgule avant la fermeture, alors que les parenthèses ne le sont pas. C'est juste une bizarrerie de la syntaxe).
    • Avec un signe de dollar en tête, ${VAR} est un expansion des paramètres en élargissant à la valeur d'une variable, avec d'éventuelles transformations supplémentaires.
  • ((…)) Les doubles parenthèses entourent un instruction arithmétique c'est-à-dire un calcul sur des entiers, avec une syntaxe ressemblant à celle des autres langages de programmation. Cette syntaxe est surtout utilisée pour les affectations et dans les conditionnels.
    • La même syntaxe est utilisée dans les expressions arithmétiques $((…)) qui s'étendent à la valeur entière de l'expression.
  • [[ … ]] entourage à double parenthèse expressions conditionnelles . Les expressions conditionnelles sont principalement construites sur opérateurs comme -n $variable pour tester si une variable est vide et -e $file pour tester si un fichier existe. Il existe également des opérateurs d'égalité de chaînes de caractères : "$string1" == "$string2" (attention au fait que le côté droit est un motif, par ex. [[ $foo == a* ]] vérifie si $foo commence par a tandis que [[ $foo == "a*" ]] vérifie si $foo est exactement a* ), et le familier ! , && et || des opérateurs de négation, de conjonction et de disjonction, ainsi que des parenthèses pour le regroupement. Notez que vous avez besoin d'un espace autour de chaque opérateur (par ex. [[ "$x" == "$y" ]] pas [[ "$x"=="$y" ]] ), et un espace ou un caractère comme ; à l'intérieur et à l'extérieur des parenthèses (par ex. [[ -n $foo ]] pas [[-n $foo]] ).
  • [ … ] Les parenthèses simples sont une forme alternative d'expressions conditionnelles avec plus de bizarreries (mais plus anciennes et plus portables). N'en écrivez pas pour l'instant ; commencez à vous en préoccuper lorsque vous trouverez des scripts qui en contiennent.

C'est la manière idiomatique d'écrire votre test en bash :

if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then

Si vous avez besoin d'une portabilité vers d'autres shells, c'est ce qu'il faut faire (notez les guillemets supplémentaires et les séries de parenthèses séparées autour de chaque test individuel, et l'utilisation du traditionnel = plutôt que l'opérateur ksh/bash/zsh == variante) :

if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

38 votes

Excellent article, le résumé des parenthèses est tout simplement idéal.

11 votes

Il est préférable d'utiliser == pour différencier la comparaison de l'assignation d'une variable (qui est également = )

0 votes

+1 @WillSheppard pour votre rappel du style approprié. Gilles, n'avez-vous pas besoin d'un point-virgule après votre crochet fermant et avant "then" ? J'ai toujours pensé que if , then , else et fi ne pouvaient pas être sur la même ligne... Comme dans : if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

38voto

matchew Points 5196

Très proche

if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]]; 
  then 
    scale=0.05
  fi

devrait fonctionner.

la décomposition

[[ $varA -eq 1 ]] 

est une comparaison de nombres entiers où comme

$varB == 't1'

est une comparaison de chaînes de caractères. Sinon, je ne fais que regrouper les comparaisons correctement.

Les doubles crochets délimitent une expression conditionnelle. Et, je trouve que ce qui suit est une bonne lecture sur le sujet : ["(IBM) Démystifier le test, [, [, ((, et if-then-else"](http://www.ibm.com/developerworks/library/l-bash-test/index.html)

0 votes

Juste pour être sûr : la citation dans 't1' n'est pas nécessaire, n'est-ce pas ? Parce que contrairement aux instructions arithmétiques entre doubles parenthèses, où t1 serait une variable, t1 dans une expression conditionnelle en double parenthèses est juste une chaîne littérale. C'est-à-dire, [[ $varB == 't1' ]] est exactement la même chose que [[ $varB == t1 ]] n'est-ce pas ?

9voto

J.P. Tosoni Points 315

Une version très portable (même pour les anciens shells bourne) :

if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then    do-something
fi

Cela présente la qualité supplémentaire de n'exécuter qu'un seul sous-processus au maximum (qui est le processus [ ), quelle que soit la saveur de la coquille.

Remplacer = avec -eq si les variables contiennent des valeurs numériques, par exemple

  • 3 -eq 03 est vrai, mais
  • 3 = 03 est fausse. (comparaison de chaînes de caractères)

6voto

tlc Points 51

Voici le code de la version courte de l'instruction if-then-else :

( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"

Faites attention aux points suivants :

  1. || et && Les opérandes à l'intérieur de la condition if (c'est-à-dire entre les parenthèses rondes) sont des opérandes logiques (ou/et).

  2. || et && les opérandes en dehors de la condition if signifient alors/seulement

En pratique, la déclaration dit :

Si (a=1 ou b=2), alors "ok" sinon "nok".

0voto

if ([ $NUM1 == 1 ] || [ $NUM2 == 1 ]) && [ -z "$STR" ]
then
    echo STR is empty but should have a value.
fi

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X