Quitter un script en cas d'erreur

141

Je construis un script Shell qui a une iffonction comme celle-ci:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables
fi

...

Je souhaite que l'exécution du script se termine après l'affichage du message d'erreur. Comment puis-je faire ceci?

Nathan Campos
la source

Réponses:

137

Cherchez-vous exit?

C'est le meilleur guide de bash. http://tldp.org/LDP/abs/html/

Dans le contexte:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables 1>&2
    exit 1 # terminate and indicate error
fi

...
Byron Whitlock
la source
5
Si vous aimez l'ABS, vous adorerez les BashGuide , BashFAQ et BashPitfalls .
Suspendu jusqu'à nouvel ordre.
Ces liens Bash sont géniaux! Le BashFAQ serait mieux positionné en tant que BashRecipes.
Pete Alvin
337

Si vous mettez set -eun script, le script se terminera dès qu'une commande à l'intérieur échoue (c'est-à-dire dès qu'une commande retourne un statut différent de zéro). Cela ne vous permet pas d'écrire votre propre message, mais souvent les propres messages de la commande défaillante suffisent.

L'avantage de cette approche est qu'elle est automatique: vous ne courez pas le risque d'oublier de traiter un cas d'erreur.

Les commandes dont l'état est testé par un conditionnel (tel que if, &&ou ||) ne terminent pas le script (sinon le conditionnel serait inutile). Un idiome pour la commande occasionnelle dont l'échec n'a pas d'importance est command-that-may-fail || true. Vous pouvez également set -edésactiver pour une partie du script avec set +e.

Gilles 'SO- arrête d'être méchant'
la source
3
Selon mywiki.wooledge.org/BashFAQ/105 - cette fonctionnalité a toujours été obscure et alambiquée dans sa détermination des codes d'erreur des commandes qui provoquent une sortie automatique. De plus, "les règles changent d'une version de Bash à une autre, car Bash tente de suivre la définition POSIX extrêmement glissante de cette 'fonctionnalité'". Je suis d'accord avec @Dennis Williamson et la réponse acceptée de stackoverflow.com/questions/19622198/… - utilisez le trap 'error_handler' ERR. Même si c'est un piège!
Bondolin
3
l'utilisation de l' -xindicateur avec l' -eindicateur suffit souvent pour indiquer où se trouve votre programme à la sortie. Cela implique que l'utilisateur du script est également le développeur.
Alex
Bien mais je pense que l'OP avait besoin de quitter le script à partir d'une exception auto-définie.
vdegenne le
42

Si vous voulez être capable de gérer une erreur au lieu de quitter aveuglément, au lieu d'utiliser set -e, utilisez un trapsur le ERRpseudo-signal.

#!/bin/bash
f () {
    errorCode=$? # save the exit code as the first thing done in the trap function
    echo "error $errorCode"
    echo "the command executing at the time of the error was"
    echo "$BASH_COMMAND"
    echo "on line ${BASH_LINENO[0]}"
    # do some error handling, cleanup, logging, notification
    # $BASH_COMMAND contains the command that was being executed at the time of the trap
    # ${BASH_LINENO[0]} contains the line number in the script of that command
    # exit the script or return to try again, etc.
    exit $errorCode  # or use some other value or do return instead
}
trap f ERR
# do some stuff
false # returns 1 so it triggers the trap
# maybe do some other stuff

D'autres traps peuvent être configurés pour gérer d'autres signaux, y compris les signaux Unix habituels plus les autres pseudo signaux Bash RETURNet DEBUG.

Suspendu jusqu'à nouvel ordre.
la source
8

Voici comment procéder:

#!/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 *** 
************
'
supercobra
la source
Pourquoi le message DONE à stderr?
MattBianco
1
Il s'agit d'une pratique courante afin que vous puissiez diriger la sortie de votre script vers stdout afin qu'un autre processus puisse l'obtenir sans avoir les messages d'information au milieu.
supercobra
2
Il est probablement tout aussi courant de traiter tout ce qui se trouve sur stderr comme une indication de problèmes.
MattBianco
1
Dans le passé, "set -e" a toujours fonctionné pour moi, mais ce soir, j'ai rencontré une situation dans une image Alpine Linux Docker où cela n'avait aucun effet. Cette solution a fonctionné pour moi et m'a permis de revenir sur la tâche à accomplir. Très appréciée.
synthesizerpatel
@supercobra Pratique courante? Où?
Thorbjørn Ravn Andersen
-8

exit 1est tout ce dont vous avez besoin. Le 1est un code de retour, vous pouvez donc le changer si vous voulez, par exemple, 1signifier une exécution réussie et -1signifier un échec ou quelque chose comme ça.

DGH
la source
13
Sous Unix, le succès est toujours égal à 0. Cela peut aider lors de l'utilisation de testou &&ou ||.
mouviciel
5
Pour développer le commentaire de mouviciel: dans les scripts shell, 0 signifie toujours succès, et 1 à 255 signifie échec. -1 est hors de portée (et aura souvent le même effet que 255, donc un échec comme 1).
Gilles 'SO- arrête d'être diabolique'
@mouviciel, @Gilles: Merci pour les infos supplémentaires. Cela fait un moment que je n'ai pas eu affaire à bash.
DGH
Ceci est un mauvais exemple d'utilisation du code de retour, sinon ce serait une excellente réponse.
Brad Koch
1
En plus de recommander incorrectement 1 pour succès, -1 n'est pas possible (les codes de sortie ne sont pas signés).
tripleee