J'ai un script bash qui utilise de set -o errexit
sorte qu'en cas d'erreur, le script entier se termine au point d'échec.
Le script exécute une curl
commande qui ne parvient pas parfois à récupérer le fichier prévu - cependant, lorsque cela se produit, le script ne quitte pas l'erreur.
J'ai ajouté une for
boucle à
- faire une pause de quelques secondes puis réessayer la
curl
commande - utilisez
false
au bas de la boucle for pour définir un état de sortie non nul par défaut - si la commande curl réussit - la boucle se brise et l'état de sortie de la dernière commande doit être zéro.
#! /bin/bash
set -o errexit
# ...
for (( i=1; i<5; i++ ))
do
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
if [ -f ~/.vim/autoload/pathogen.vim ]
then
echo "file has been retrieved by curl, so breaking now..."
break;
fi
echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
sleep 5
# exit with non-zero status so main script will errexit
false
done
# rest of script .....
Le problème est que lorsque la curl
commande échoue, la boucle réessaye cinq fois - si toutes les tentatives échouent, la boucle for se termine et le script principal reprend - au lieu de déclencher le errexit
.
Comment puis-je obtenir la fermeture du script entier si cette curl
instruction échoue?
la source
true
avant l'instruction break pour être explicite et garantir la valeur de sortie de la boucle?exit 1
quand tout simplementexit
aurait fonctionné. C'est, cependant, une question de style et d'autres peuvent avoir leurs propres opinions.exit
comme une simple sortie - qui termine le script à part entière.exit 1
me lirait comme un "signal" à un autre processus (ieerrexit
) - qu'il devrait terminer le script en fonction du "résultat" deexit 1
. - donc je suis parti avecexit
mais merci pour l'explicationexit 1
. Cela n'affecte paserrexit
du tout. Il indique simplement au programme appelant que quelque chose s'est mal passé. Lafalse
commande contient une instruction:exit(1)
. 99,9% des commandes Unix renvoient 0 en cas de succès et non nul en cas d'erreur. Le vôtre aussi.Si vous l'avez
errexit
défini, l'false
instruction doit entraîner la fermeture immédiate du script. Même chose si lacurl
commande a échoué.Votre exemple de script, tel qu'écrit, devrait se terminer après la première
curl
défaillance de la commande la première fois qu'il appellefalse
si errexit est défini.Pour voir comment cela fonctionne (j'utilise le raccourci
-e
pour définirerrexit
:Donc, si la
curl
commande s'exécute plus d'une fois, ce script n'a pas étéerrexit
défini.la source
set -e
est plus subtil que ça. Il ne se fermera pas après la première commande ayant échoué dans une boucle. Vous pouvez le prouver vous-même en exécutant(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )
et en notant que le code s'exécutefalse
quatre fois. Pour en savoir plusset -e
, consultez la FAQ # 105 de Greg .errexit
pas établies. Veuillez appliquer la logique au script de la question. Exécutez ceci:(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here )
Oui, le test des valeurs de retour avecif
while
||
&&
etc ne déclenche pas errexit. Le script d'origine ne faisait pas||
la boucle for.set -o errexit
commande dans mon exemple de code, je l'ai ajoutée maintenant - et pour moi, ce n'était pas une erreur de sortie comme prévu. Je devais garder lafalse
dernière commande dans la boucle for, puis fermer la boucle avecdone || exit [1]
- alors cela a bien fonctionné!set -o errexit
peut être délicat dans les boucles et les sous-coquilles, car vous devez repousser le chemin du processus.La rupture d'une boucle (même en fonctionnement normal) est considérée comme une mauvaise pratique. Vous pouvez m'appeler old-school pour préférer une boucle while plutôt qu'une boucle for pour deux conditions, mais je trouve préférable de lire:
la source
Si
errexit
est défini et que lacurl
commande échoue, le script se termine juste après l'échec de la commande curl. Dans le manuel bash, il n'y a aucun indice quiset -e
ignore tout état de retour échoué d'un single dans une commande composée. Ce ne serait le cas que si la commande composée est exécutée dans un contexte oùset -e
est ignoré.https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin
Essayez un exemple légèrement adapté publié par RobertL. Cela s'arrête à la première for-itération juste après la fausse commande:
la source
Vous pouvez simplement ajouter l'option --fail à la commande curl, cela résoudra votre problème, le script échouera et sortira en cas d'erreur si la commande curl échoue, si très utile aussi lors de l'utilisation de curl dans le pipeline jenkins:
la source