Utilisation déroutante de && et || les opérateurs

94

Je parcourais un /etc/rc.d/init.d/sendmailfichier (je sais que ce n'est presque jamais utilisé, mais j'étudie pour un examen) et je suis devenu un peu confus à propos &&des ||opérateurs et des opérateurs. J'ai lu où ils peuvent être utilisés dans des déclarations telles que:

if [ test1 ] && [ test2 ]; then
     echo "both tests are true"
elif [ test1 ] || [ test2 ]; then
     echo "one test is true"
fi

Cependant, ce script affiche des instructions d'une seule ligne telles que:

[ -z "$SMQUEUE" ] && SMQUEUE="QUEUE"
[ -f /usr/sbin/sendmail ] || exit 0

Ceux-ci semblent utiliser les opérateurs &&et ||pour obtenir des réponses sur la base de tests, mais je n'ai pas été en mesure de trouver de documentation sur l'utilisation particulière de ces opérateurs. Quelqu'un peut-il expliquer ce que cela fait dans ce contexte particulier?

josh-cain
la source

Réponses:

141

Le côté droit de &&ne sera évalué que si le statut de sortie du côté gauche est zéro (c'est-à-dire vrai). ||est le contraire: il évaluera le côté droit uniquement si le statut de sortie du côté gauche est différent de zéro (c'est-à-dire faux).

Vous pouvez considérer [ ... ]être un programme avec une valeur de retour. Si le test intérieur a la valeur true, il renvoie zéro. sinon, il renvoie non nul.

Exemples:

$ false && echo howdy!

$ true && echo howdy!
howdy!
$ true || echo howdy!

$ false || echo howdy!
howdy!

Notes supplémentaires:

Si vous le faites which [, vous verrez peut-être que [cela pointe effectivement vers un programme! Ce n'est généralement pas réellement celui qui s'exécute dans les scripts, cependant; courir type [pour voir ce qui se passe réellement. Si vous wan pour essayer d' utiliser le programme, juste donner le chemin complet comme ceci: /bin/[ 1 = 1.

Shawn J. Goff
la source
6
Lorsque vous voyez "X ou Y", vous testez X. Si c'est vrai, vous connaissez déjà la réponse à "X ou Y" (c'est vrai), vous n'avez donc pas besoin de tester Y. Si c'est vrai, vous ne connaissez pas le répondez à "X ou Y", vous devez donc tester Y. Lorsque vous voyez "X et Y", vous testez X. Si c'est faux, vous connaissez déjà la réponse à "X et Y" (c'est faux), alors pas besoin de tester Y. Si X est vrai, alors vous devez tester Y pour voir si "X et Y" est vrai.
David Schwartz
2
Au lieu de "si le côté gauche renvoie zéro", j'écrirais "si l'état de sortie de la commande du côté gauche est zéro". Je trouve "return" un peu ambigu, car la sortie et l'état de sortie peuvent tous deux être considérés comme des "valeurs de retour"
glenn jackman
Non seulement pouvez - vous « considérer [ ... ] comme un programme », dans de nombreux cas , il est . C'est généralement dans le fichier /bin/[ou /usr/bin/[.
LS
5
Les programmeurs C trouveront cela très déroutant. Là 0 signifie faux ... Alors que dans shellscripting 0 signifie vrai ... Esprit soufflé.
Calmarius
Vous pouvez en mentionner un autre à la testplace de ifou [. Et if [et if testsemblent être entrecoupés de [et testsans rime apparente ni raison. testse présente parfois, comme sur config.site pour les librairies du fournisseur sur Fedora x86_64 .
60

Voici mon aide-mémoire:

  • "A; B" Exécuter A puis B, quel que soit le succès de A
  • "A && B" Exécuter B si A réussit
  • "A || B" Exécuter B si A échoue
  • "A &" Run A en arrière-plan.
utilisateur177073
la source
Il existe quelques parallèles de calcul lambda intéressants mis en évidence ici en JavaScript (définition des variables dans l’ordre); "left (aka vrai)": (a => b => a). "droite (aka false)": (a => b => b). "A; B" "alors" (a => b => (() => b())(a())). "A && B" "si sans autre (quand)" (a => b => a()(() => right)(b)). "A || B" "sinon sans si (sauf)" (a => b => a()(b)(() => right)). "a && b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Dmitry
1
notez que dans bash, left est analogue 0 / chaîne vide, right analogue est tout le reste.
Dmitry
28

développer sur la réponse de @ Shawn-j-Goff d'en haut, &&est un ET logique et ||un OU logique.

Reportez - vous à cette partie du Advanced Bash Scripting Guide. Certains des contenus du lien pour la référence de l'utilisateur comme ci-dessous.

&& ET

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
#  Note that && operator not permitted inside brackets
#+ of [ ... ] construct.

|| OU

if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 || $condition2 ]]    # Also works.
#  Note that || operator not permitted inside brackets
#+ of a [ ... ] construct.
Tim Kennedy
la source
12

D'après mon expérience, j'utilise les && et || pour réduire une instruction if à une seule ligne.

Supposons que nous recherchions un fichier appelé /root/Sample.txt, l'itération traditionnelle serait la suivante dans le shell:

if [ -f /root/Sample.txt ]
then
    echo "file found"
else
    echo "file not found"
fi

Ces 6 lignes peuvent être réduites à une seule ligne:

[[ -f /root/Sample.txt ]] && echo "file found" || echo "file not found"

Lorsque vous exécutez quelques itérations pour définir des variables ou pour créer des fichiers, etc., la vie est plus facile et le script a l'air plus lisse en utilisant une seule ligne si la fonction est utilisée, mais l'inconvénient est qu'il devient un peu plus difficile d'implémenter plusieurs commandes à partir d'une seule itération. vous pouvez utiliser des fonctions.

syme89
la source
C'est cool. Me rappelle le code objc (a == b)? Val = 1: val = 2;
GeneCode
Comment utiliser cette commande lorsque je souhaite exécuter un processus en arrière-plan avec "&"? Je reçois une erreur de syntaxe pour./someScript.sh & && echo 'ok' || echo 'ko'
Katie
4

Il existe une notion de "coupe courte".

Quand (expr1 && expr2)est évalué - expr2n'est évalué que s'il est exp1évalué à "true". C'est parce que expr1ET expr2doivent être vrais pour (expr1 && expr2)être vrais. Si expr1évalué à "false" expr2n'est PAS évalué (raccourci) car (expr1 && expr2)est déjà "flase".

Essayez ce qui suit - supposez que le fichier F1existe et que le fichier F2n'existe pas:

( [ -s F1 ] && echo "File Exists" )  # will print "File Exists" - no short cut
( [ -s F2 ] && echo "File Exists" )  # will NOT print "File Exists" - short cut

De même pour ||(ou) - mais la coupe courte est inversée.

Larry
la source
5
La logique est généralement appelée "court-circuit". Je n'ai jamais vu l'expression "coupe courte" utilisée. Je mentionne cela pour aider à trouver des références.
LS
-1

Les exemples cités dans la réponse de Shawn J. Goff sont corrects, mais l'explication est l'inverse. Vérifiez s'il vous plaît:

Le côté droit de && ne sera évalué que si le statut de sortie du côté gauche est NONZERO. || est le contraire: il évaluera le côté droit uniquement si le statut de sortie du côté gauche est ZERO.

Try2Help
la source
3
Vous savez que pour les shells, le code de sortie zéro est évalué à true et donc, le code de sortie différent de zéro du côté gauche des &&résultats dans l'expression entière pour renvoyer false ?
contre-mode
1
Quelqu'un n'a pas approuvé vos modifications car ce n'était pas votre réponse. Si vous pensez que certaines réponses sont incorrectes, vous devriez les annuler et éventuellement laisser un commentaire. si vous pensez que cela nécessite un changement, vous devez laisser un commentaire. L’édition sert à corriger les fautes de grammaire, de formatage et d’orthographe qui ne changent pas le sens de la réponse.
Techraf
1
@countermode Je suis désolé, vous avez raison, je pensais sous Linux zéro = faux et non nul = vrai (comme dans C et beaucoup d'autres langages / environnements / plates-formes). Je m'excuse pour le malentendu.
Try2Help