Quelle est la différence entre les méthodes de chaînage de commandes suivantes?
cmd1; cmd2
cmd1 && cmd2
Supposons qu'il y ait command1 && command2
.
Dans ce cas command2
sera exécuté si et seulement si command1
n'a renvoyé aucun état de sortie.
;
n'est qu'un séparateur de commandes. Donc command2
sera exécuté quel que soit command1
revenu.
$> [[ "a" = "b" ]] && echo ok
$> [[ "a" = "b" ]]; echo ok
ok
cmd1; cmd2
exécute cmd1
, puis cmd2
, peu importe ce que. C'est exactement équivalent à mettre cmd1
et cmd2
sur des lignes séparées¹. Le statut de retour de cette commande composée est celui de cmd2
.
cmd1 && cmd2
exécute cmd1
. Ensuite, si l'état de sortie de cmd1
est zéro, cmd2
est exécuté. Le statut de retour de cette commande composée est celui de cmd1
s'il est différent de zéro (donc cmd2
n'a pas fonctionné), et celle de cmd2
sinon (s'il a fonctionné).
if cmd1; then cmd2; fi
est principalement équivalent à cmd1 && cmd2
. La principale différence est que la version avec if
renvoie 0 si cmd1
renvoie un statut différent de zéro.
Une commande renvoie 0 pour indiquer la réussite et un code d'erreur différent de zéro (entre 1 et 255, généralement entre 1 et 125 car les valeurs supérieures ont d'autres significations) pour indiquer l'échec. Donc cmd1; cmd2
signifie "exécuter ces commandes dans l'ordre, peu importe", tandis que cmd1 && cmd2
signifie "exécuter ces commandes, mais arrêtez immédiatement si la première commande échoue".
Vous pouvez demander au shell de passer en mode "sortie en cas d'erreur" en exécutant set -e
. Dans ce mode, le shell se ferme dès qu'une commande renvoie un état différent de zéro, sauf dans les constructions conditionnelles (le côté gauche de &&
ou ||
, la partie condition de if
et while
). Ainsi, sous set -e
, ;
(ou une nouvelle ligne) équivaut effectivement à &&
².
¹ En termes de flux de contrôle, c'est. Les retours à la ligne et les points-virgules sont exécutés exactement de la même manière, mais ils ne sont pas analysés exactement de la même manière, par ex. alias ls=true; ls
exécute ls
et non true
car l'analyseur effectue une résolution d'alias sur ls
avant d'exécuter la définition d'alias.
¹ Cela ne veut pas dire que vous pouvez remplacer aveuglément &&
par ;
si vous avez ajouté set -e
. Par exemple, ;
a une priorité inférieure à &&
, donc cmd1 && cmd2 || cmd3
est équivalent à set -e; { cmd1; cmd2; } || cmd3
. Aussi, set -e
interagit mal avec les sous-coquilles - les détails dérailleraient trop cette réponse.
La première ligne exécutera une commande après l'autre, que la première ait réussi ou non. La deuxième ligne est un exemple de logique Shell: elle n'exécutera la deuxième commande que si la première a réussi. Ceci est dû au fait &&
est logique and
. Par conséquent, si la première commande échoue, l'état logique de la ligne entière est connu pour être faux et il n'est pas nécessaire d'évaluer la deuxième commande.
Plus pratique, il y a une différence entre
cd /backup/old; rm -rf -- *
et
cd /backup/old && rm -rf -- *
. En plus, c'est une façon stupide, le premier supprimera tout votre système de fichiers (ou $ HOME, selon la façon dont il est appelé) car il exécute rm
indépendamment du fait que cd
ait réussi ou non.