Les opérateurs &&
et ne||
sont pas des remplacements inline exacts pour if-then-else. Bien que utilisés avec précaution, ils peuvent accomplir à peu près la même chose.
Un seul test est simple et sans ambiguïté ...
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
Cependant, essayer d'ajouter plusieurs tests peut donner des résultats inattendus ...
[[ A == A ]] && echo TRUE || echo FALSE # TRUE (as expected)
[[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
[[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
[[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)
Pourquoi les échos FALSE et TRUE sont-ils tous les deux ?
Ce qui se passe ici, c'est que nous ne le réalisons pas &&
et que nous sommes des ||
opérateurs surchargés qui agissent différemment entre crochets de test conditionnels [[ ]]
et dans la liste AND et OR (exécution conditionnelle) que nous avons ici.
De la page de manuel bash (modifiée) ...
Listes
Une liste est une séquence d'un ou de plusieurs pipelines séparés par l'un des opérateurs;, &, &&, ou ││ et éventuellement terminés par l'un des;;, ou. De ces opérateurs de liste, && et ││ ont la même priorité, suivis de; et &, qui ont la même préséance.
Une séquence d'un ou plusieurs traits nouveaux peut apparaître dans une liste au lieu d'un point-virgule pour délimiter les commandes.
Si une commande est terminée par l'opérateur de contrôle &, le shell l'exécute en arrière-plan dans un sous-shell. Le shell n'attend pas la fin de la commande et le statut de retour est 0. Commandes séparées par un; sont exécutés séquentiellement; le shell attend que chaque commande se termine à son tour. Le statut de retour est le statut de sortie de la dernière commande exécutée.
Les listes AND et OR sont des séquences d'un ou plusieurs pipelines séparés par les opérateurs de contrôle && et, respectivement. Les listes AND et OR sont exécutées avec une associativité à gauche.
Une liste AND a la forme ...
command1 && command2
Command2 est exécuté si et seulement si command1 renvoie un état de sortie égal à zéro.
Une liste OR se présente sous la forme ...
command1 ││ command2
Command2 est exécuté si et seulement si command1 renvoie un état de sortie différent de zéro.
Le statut de retour des listes AND et OR est le statut de sortie de la dernière commande exécutée dans la liste.
Revenons à notre dernier exemple ...
[[ A == B ]] || echo FALSE && echo TRUE
[[ A == B ]] is false
|| Does NOT mean OR! It means...
'execute next command if last command return code(rc) was false'
echo FALSE The 'echo' command rc is always true
(i.e. it successfully echoed the word "FALSE")
&& Execute next command if last command rc was true
echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"
D'accord. Si c'est le cas, pourquoi l'avant-dernier exemple fait-il écho à quoi que ce soit?
[[ A == A ]] || echo FALSE && echo TRUE
[[ A == A ]] is true
|| execute next command if last command rc was false.
echo FALSE Since last rc was true, shouldn't it have stopped before this?
Nope. Instead, it skips the 'echo FALSE', does not even try to
execute it, and continues looking for a `&&` clause.
&& ... which it finds here
echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"
Le risque d'erreurs logiques lors de l'utilisation de plus d'une &&
ou ||
dans une liste de commandes est assez élevé.
Recommandations
Un simple &&
ou ||
dans une liste de commandes fonctionne comme prévu, donc c'est assez sûr. S'il s'agit d'une situation dans laquelle vous n'avez pas besoin d'une clause else, les éléments suivants peuvent être plus clairs à suivre (les accolades sont nécessaires pour regrouper les 2 dernières commandes) ...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
Les opérateurs multiples &&
et ||
où chaque commande, à l'exception de la dernière, est un test (c'est-à-dire entre crochets [[ ]]
), sont également sécurisés, car tous les opérateurs sauf le dernier se comportent comme prévu. Le dernier opérateur agit plutôt comme une clause then
ou else
.
&&
et||
shell en tant quecmd1 && cmd2 || cmd3
aient la même priorité, les commandes&&
in((...))
et[[...]]
ont la priorité sur||
(((a || b && c))
est((a || (b && c)))
). Même chose pour-a
/-o
danstest
/[
etfind
et&
/|
dansexpr
.