web-dev-qa-db-fra.com

Dans un script Bash, comment puis-je quitter l'intégralité du script si une certaine condition se produit?

J'écris un script dans Bash pour tester du code. Cependant, il semble absurde d'exécuter les tests si la compilation du code échoue en premier lieu. Dans ce cas, je vais simplement abandonner les tests.

Y a-t-il un moyen de faire cela sans insérer le script entier dans une boucle while et sans utiliser de pauses? Quelque chose comme un dun dun dun goto?

532
samoz

Essayez cette déclaration:

exit 1

Remplacez 1 par les codes d'erreur appropriés. Voir aussi Codes de sortie ayant une signification spéciale .

583
Michael Foukarakis

Utilisez set -e

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2

Le script se terminera après la première ligne qui a échoué (retourne un code de sortie différent de zéro). Dans ce cas, command-that-fail2 ne s'exécutera pas.

Si vous deviez vérifier le statut de retour de chaque commande, votre script ressemblerait à ceci:

#!/bin/bash

# I'm assuming you're using make

cd /project-dir
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

Avec set -e cela ressemblerait à:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make

Toute commande qui échoue entraîne l'échec du script entier et renvoie un statut de sortie que vous pouvez vérifier avec $? . Si votre script est très long ou que vous construisez beaucoup de choses, cela va devenir assez moche si vous ajoutez des contrôles d'état des retours partout.

607
Shizzmo

Un mec SysOps insolent m'a appris la technique de la griffe à trois doigts:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }

Ces fonctions sont * NIX OS et Shell robustes. Placez-les au début de votre script (bash ou autre), try() votre déclaration et votre code.

Explication

(basé sur mouton volant commentaire).

  • yell: affiche le nom du script et tous les arguments dans stderr:
    • $0 est le chemin du script;
    • $* sont tous des arguments. 
    • >&2 signifie que > REDIRIGE LA SORTIE STANDARD VERS & PIPE 2. pipe 1 serait stdout lui-même. 
  • die fait la même chose que yell, mais quitte avec un état de sortie non-0, ce qui signifie «échec». 
  • try utilise le || (boolean OR), qui évalue uniquement le côté droit si le côté gauche n’a pas échoué.
    • $@ est encore tous les arguments, mais différent

J'espère que ça explique tout.

174
c.gutierrez

Si vous appelez le script avec source, vous pouvez utiliser return <x><x> sera le statut de sortie du script (utilisez une valeur différente de zéro pour error ou false). Cela fonctionnera également comme prévu lorsque vous source le script, mais si vous appelez un script exécutable (c.-à-d. Directement avec son nom de fichier), l'instruction return renvoie une plainte (le message d'erreur "return: can only" return "d'un fonction ou script source ").

Si exit <x> est utilisé à la place, lorsque le script est appelé avec source, le shell qui l'a démarré est quitté, mais un script exécutable s'exécute directement correctement.

Pour traiter l'un ou l'autre cas dans le même script, vous pouvez utiliser

return <x> 2> /dev/null || exit <x>

Ceci gérera n'importe quelle invocation qui conviendra.

Note: <x> est supposé être juste un nombre.

21
kavadias

J'inclus souvent une fonction appelée run () pour gérer les erreurs. Chaque appel que je veux passer est passé à cette fonction afin que le script complet se ferme lorsqu'un échec survient. L'avantage de cette solution par rapport à set -e est que le script ne se ferme pas de manière silencieuse lorsqu'une ligne échoue et peut vous dire quel est le problème. Dans l'exemple suivant, la 3ème ligne n'est pas exécutée car le script se ferme lors de l'appel de false.

function run() {
  cmd_output=$(eval $1)
  return_value=$?
  if [ $return_value != 0 ]; then
    echo "Command $1 failed"
    exit -1
  else
    echo "output: $cmd_output"
    echo "Command succeeded."
  fi
  return $return_value
}
run "date"
run "false"
run "date"
10
Joseph Sheedy

Au lieu de la construction if, vous pouvez utiliser l'évaluation l'évaluation du court-circuit :

#!/usr/bin/env bash

echo $[1+1]
echo $[2/0]              # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]

Notez la paire de parenthèses qui est nécessaire en raison de la priorité de l'opérateur d'alternance. $? est une variable spéciale définie pour quitter le code de la dernière commande appelée.

5
skalee

J'ai la même question mais je ne peux pas la poser car ce serait un doublon.

La réponse acceptée, en utilisant exit, ne fonctionne pas lorsque le script est un peu plus compliqué. Si vous utilisez un processus en arrière-plan pour vérifier la condition, exit ferme uniquement ce processus, car il s'exécute dans un sous-shell. Pour tuer le script, vous devez explicitement le tuer (du moins, c'est le seul moyen que je connaisse).

Voici un petit script sur la façon de le faire:

#!/bin/bash

boom() {
    while true; do sleep 1.2; echo boom; done
}

f() {
    echo Hello
    N=0
    while
        ((N++ <10))
    do
        sleep 1
        echo $N
        #        ((N > 5)) && exit 4 # does not work
        ((N > 5)) && { kill -9 $$; exit 5; } # works 
    done
}

boom &
f &

while true; do sleep 0.5; echo beep; done

C’est une meilleure réponse, mais toujours incomplète. Je ne sais vraiment pas comment me débarrasser de la boum partie.

0
Gyro Gearloose