web-dev-qa-db-fra.com

Abandonner un script Shell si une commande renvoie une valeur différente de zéro?

J'ai un script Bash Shell qui appelle un certain nombre de commandes. J'aimerais que le script shell se ferme automatiquement avec une valeur de retour de 1 si l'une des commandes renvoie une valeur non nulle.

Est-ce possible sans vérifier explicitement le résultat de chaque commande?

par exemple.

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi
390
Jin Kim

Ajoutez ceci au début du script:

set -e

Cela entraînera la fermeture immédiate du shell si une commande simple se ferme avec une valeur de sortie différente de zéro. Une commande simple est une commande ne faisant pas partie d'un if, While, ou tant que test, ou d'une partie d'un && ou || liste.

Reportez-vous à la page de manuel bash (1) de la commande interne "set" pour plus de détails.

Personnellement, je lance presque tous les scripts Shell avec "set -e". C'est vraiment énervant de continuer obstinément un script quand quelque chose échoue au milieu et rompt les hypothèses pour le reste du script.

676
Ville Laurikari

Pour ajouter à la réponse acceptée:

Gardez à l'esprit que set -e n'est parfois pas assez, surtout si vous avez des pipes.

Par exemple, supposons que vous ayez ce script

#!/bin/bash
set -e 
./configure  > configure.log
make

... qui fonctionne comme prévu: une erreur dans configure interrompt l'exécution.

Demain, vous apportez un changement apparemment trivial:

#!/bin/bash
set -e 
./configure  | tee configure.log
make

... et maintenant ça ne marche pas. Ceci est expliqué ici , et une solution de contournement (Bash uniquement) est fournie:

 #!/bin/bash 
 régler -e 
set -o pipefail
 
 ./ configure | tee configure.log 
 make 
186
leonbloy

Les déclarations if dans votre exemple sont inutiles. Fais-le comme ça:

dosomething1 || exit 1

Si vous suivez les conseils de Ville Laurikari et utilisez set -e, vous devrez peut-être utiliser certaines commandes:

dosomething || true

Le || true donnera au pipeline de commandes une valeur de retour true même si la commande échoue pour que l'option -e ne tue pas le script.

77
Zan Lynx

Si vous avez un nettoyage à faire à la sortie, vous pouvez également utiliser 'trap' avec le pseudo-signal ERR. Cela fonctionne de la même manière que l’interception de INT ou de tout autre signal; bash renvoie ERR si une commande se termine avec une valeur différente de zéro:

# Create the trap with   
#    trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Partially turn off the trap.
trap - ERR
# Now a control-C will still cause cleanup, but
# a nonzero exit code won't:
ps aux | grep blahblahblah

Ou, surtout si vous utilisez "set -e", vous pouvez capturer EXIT; votre interruption sera alors exécutée lorsque le script se terminera pour une raison quelconque, y compris une fin normale, des interruptions, une sortie provoquée par l'option -e, etc.

27
fholo

Exécutez-le avec -e ou set -e en haut.

Regardez aussi set -u.

12
lumpynose

La variable $? est rarement nécessaire. Le pseudo-idiome command; if [ $? -eq 0 ]; then X; fi devrait toujours être écrit sous la forme if command; then X; fi.

Le cas où $? est requis est le cas où il doit être comparé à plusieurs valeurs:

command
case $? in
  (0) X;;
  (1) Y;;
  (2) Z;;
esac

ou lorsque $? doit être réutilisé ou autrement manipulé:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi
11
Mark Edgar
#!/bin/bash -e

devrait suffire.

3
Baligh Uddin

Une expression comme

dosomething1 && dosomething2 && dosomething3

arrêtera le traitement lorsque l’une des commandes retournera avec une valeur différente de zéro. Par exemple, la commande suivante n'imprimera jamais "terminé":

cat nosuchfile && echo "done"
echo $?
1
3
gabor