J'ai écrit un script Shell et je le trouverais utile s'il était possible d'arrêter l'exécution dudit script Shell si l'une des commandes échouait. Voir ci-dessous pour un exemple:
#!/bin/bash
cd some_dir
./configure --some-flags
make
make install
Donc, dans ce cas, si le script ne peut pas changer dans le répertoire indiqué, il ne voudra certainement pas faire un ./configure par la suite s'il échoue.
Maintenant, je suis bien conscient que je pourrais avoir une vérification if pour chaque commande (ce qui, à mon avis, est une solution sans espoir), mais existe-t-il un paramètre global permettant de faire quitter le script si l'une des commandes échoue?
Utilisez le set -e
intégré:
_#!/bin/bash
set -e
# Any subsequent(*) commands which fail will cause the Shell script to exit immediately
_
Vous pouvez également passer _-e
_ sur la ligne de commande:
_bash -e my_script.sh
_
Vous pouvez également désactiver ce comportement avec _set +e
_.
Vous pouvez également vouloir utiliser tout ou partie des options _-e
_ _-u
_ _-x
_ et _-o pipefail
_ comme ceci:
_set -euxo pipefail
_
_-e
_ ferme en cas d'erreur, _-u
_ erreurs sur des variables non définies et -o (for option) pipefail
se ferme en cas d'échec du canal de commande. Certains pièges et solutions de contournement sont bien documentés ici .
(*) Remarque:
Le shell fait pas quitter si la commande qui échoue fait partie de la liste de commandes suivant immédiatement un tant que ou jusqu'au mot-clé faisant partie du test suivant le si ou Elif mots réservés, faisant partie de toute commande exécutée dans un && ou || liste sauf la commande suivant la dernière && ou || , toute commande dans un pipeline sauf la dernière, ou si la valeur de retour de la commande est inversée avec !
(de _man bash
_)
Pour quitter le script dès qu'une des commandes a échoué, ajoutez ceci au début:
set -e
Cela provoque la fermeture immédiate du script lorsqu'une commande ne faisant pas partie d'un test (comme dans une condition if [ ... ]
ou une construction &&
) se ferme avec un code de sortie différent de zéro.
Voici comment faire:
#!/bin/sh
abort()
{
echo >&2 '
***************
*** ABORTED ***
***************
'
echo "An error occurred. Exiting..." >&2
exit 1
}
trap 'abort' 0
set -e
# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0
echo >&2 '
************
*** DONE ***
************
'
Utilisez-le avec pipefail
.
set -e
set -o pipefail
-e (errexit): Abandonne le script à la première erreur, lorsqu'une commande se termine avec un statut différent de zéro (sauf dans les boucles till ou while, if-tests, list)
-o pipefail: force un pipeline à renvoyer l'état de sortie de la dernière commande du canal qui a renvoyé une valeur de retour non nulle.
Une alternative à la réponse acceptée qui s'inscrit dans la première ligne:
#!/bin/bash -e
cd some_dir
./configure --some-flags
make
make install
Un idiome est:
cd some_dir && ./configure --some-flags && make && make install
Je sais que cela peut être long, mais pour les scripts plus volumineux, vous pouvez le diviser en fonctions logiques.
Je pense que ce que vous recherchez est la commande trap
:
trap command signal [signal ...]
Pour plus d'informations, voir cette page .
Une autre option consiste à utiliser la commande set -e
en haut de votre script. Le script se fermera si un programme/une commande renvoie une valeur non vraie.
Un point oublié dans les réponses existantes est de montrer comment hériter des pièges d'erreur. Le shell bash
fournit une telle option pour celle utilisant set
-E
Si défini, toute interruption sur
ERR
est héritée par les fonctions Shell, les substitutions de commandes et les commandes exécutées dans un environnement de sous-shell. Le piègeERR
est normalement not hérité dans de tels cas.
réponse d'Adam Rosenfield la recommandation d'utiliser _set -e
_ a raison dans certains cas, mais elle comporte ses propres pièges potentiels. Voir BashFAQ de GreyCat - 105 - Pourquoi set -e (ou set -o errexit, ou piège ERR) ne fait-il pas ce que j'attendais?
Selon le manuel, set -e exits
s'il s'agit d'une simple commande avec un statut différent de zéro. Le shell ne se ferme pas si la commande qui échoue fait partie de la liste de commandes suivant immédiatement un mot clé
while
ouuntil
, qui fait partie dutest in a if statement
, élément d’une liste&&
ou||
sauf le commande suivant lefinal && or ||
,any command in a pipeline but the last
ou si la valeur de retour de la commande est inversée via!
".
ce qui signifie que _set -e
_ ne fonctionne pas dans les cas simples suivants (des explications détaillées peuvent être trouvées sur le wiki)
Utilisation de l'opérateur arithmétique let
ou $((..))
(à partir de bash
4.1) pour incrémenter une valeur de variable
_#!/usr/bin/env bash
set -e
i=0
let i++ # or ((i++)) on bash 4.1 or later
echo "i is $i"
_
Si la commande incriminée fait not une partie de la dernière commande exécutée via _&&
_ ou _||
_. Par exemple le piège ci-dessous ne tirerait pas quand on s'attend à ce qu'il
_#!/usr/bin/env bash
set -e
test -d nosuchdir && echo no dir
echo survived
_
Lorsqu'il est utilisé de manière incorrecte dans une instruction if
en tant que, le code de sortie de l'instruction if
est le code de sortie de la dernière commande exécutée. Dans l'exemple ci-dessous, la dernière commande exécutée était echo
qui ne déclencherait pas l'interruption, même si le _test -d
_ a échoué.
_#!/usr/bin/env bash
set -e
f() { if test -d nosuchdir; then echo no dir; fi; }
f
echo survived
_
Lorsqu'elles sont utilisées avec une substitution de commande, elles sont ignorées, sauf si _inherit_errexit
_ est défini avec bash
4.4.
_#!/usr/bin/env bash
set -e
foo=$(expr 1-1; true)
echo survived
_
lorsque vous utilisez des commandes qui ressemblent à des affectations mais ne le sont pas, telles que export
, declare
, typeset
ou local
. Ici, l'appel de la fonction à f
va not quitter car local
a balayé le code d'erreur défini précédemment.
_set -e
f() { local var=$(somecommand that fails); }
g() { local var; var=$(somecommand that fails); }
_
Lorsqu'il est utilisé dans un pipeline, et que la commande incriminée est pas fait partie de la dernière commande. Par exemple la commande ci-dessous passerait toujours. Une option consiste à activer pipefail
en renvoyant le code de sortie du processus premier ayant échoué:
_set -e
somecommand that fails | cat -
echo survived
_
La recommandation idéale est de not utiliser _set -e
_ et de mettre en place une propre version de la vérification des erreurs. Plus d'informations sur l'implémentation du traitement d'erreur personnalisé sur l'une de mes réponses à Erreur de levée dans un script Bash