Le script bash avec «set -e» ne s'arrête pas sur la commande «… &&…»


13

J'utilise set -epour arrêter le script bash à la première erreur .

Tout fonctionne bien sauf si j'utilise la commande avec &&:

$ cat script
set -e
cd not_existing_dir && echo 123
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
I'm running! =P
$

comparé à:

$ cat script
set -e
cd not_existing_dir
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
$

Le premier exemple fait toujours écho I'm running!, mais pas le second. Pourquoi se comportent-ils différemment?

UPD. Question similaire: /programming/6930295/set-e-and-short-tests


À quoi vous attendez-vous dans le premier exemple?
Flup

@Flup Je m'attends à ce que le script s'arrête après une cdcommande infructueuse
907th

1
Voir BashFAQ # 105 pour une discussion générale des endroits où le set -ecomportement est surprenant.
Charles Duffy

Réponses:


9

Il s'agit d'un comportement documenté. La page de manuel bash (1) indique, par exemple set -e,

Le shell ne se ferme pas si la commande qui échoue fait partie de la liste de commandes immédiatement après un mot-clé whileou until, une partie du test après les mots ifou elifréservés, une partie de toute commande exécutée dans une liste &&ou|| sauf la commande suivant la finale &&ou|| , tout dans un pipeline mais le dernier, ou si la valeur de retour de la commande est inversée avec !.
[Je souligne.]

Et la spécification du langage de commande du shell POSIX confirme qu'il s'agit du comportement correct:

Le -eréglage doit être ignoré lors de l' exécution de la liste composé suivant la while, until, ifou elifmot réservé, un pipeline en commençant par le !mot réservé, ou toute commande d'un OU ET liste autre que le dernier.

et la section 2.9.3 Listes de ce document définit

Une liste ET-OU est une séquence d'un ou plusieurs pipelines séparés par les opérateurs " &&" et " ||".


9

L' set -eoption n'a pas d'effet dans certaines situations, et c'est le comportement standard et portable à travers le shell compatible POSIX.


La commande ayant échoué fait partie du pipeline:

false | true; echo printed

imprimera printed.

Et seule la défaillance du pipeline lui-même est prise en compte:

true | false; echo 'not printed'

n'imprimera rien.


La piste de commande qui a échoué dans la liste des composés suivant la while, until, if, elifmot réservé, un pipeline en commençant par le !mot réservé, ou toute commande dans le cadre de la &&ou ||liste , sauf la dernière:

false || true; echo printed

La dernière commande échoue toujours set -eaffectée:

true && false; echo 'not printed'

Le sous-shell échoue dans une commande composée:

(false; echo 'not printed') | cat -; echo printed

Je vous remercie! Il serait plus clair à utiliser echo "printed"et echo "not_printed"dans vos exemples (au lieu de echo 1).
907th

3
Notez que cela set -eprovoque une sortie dans (false && true); echo not here, mais pas dans { false && true; }; echo here, bien que YMMV avec différents shells et même différentes versions d'un même shell. Je ne toucherais pas set -eavec un poteau de barge et ferais une gestion correcte des erreurs à la place.
Stéphane Chazelas

1

ma conjecture est si-alors la condition dans son ensemble est évaluée à vrai.

j'ai essayé

set -e
if cd not_existing_dir
then  echo 123
fi
echo "I'm running! =P"

qui donne

-bash: cd: not_existing_dir: No such file or directory
I'm running! =P

le code d'erreur est catch by if condition, donc bash ne déclenchera pas la fin de l'exécution.


Mais je n'utilise pasif ... fi
907th

Je sais, c'est un si implicite.
Archemar
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.