303 votes

Comment sortir si une commande a échoué ?

Je suis un noob en shell-scripting. Je veux imprimer un message et quitter mon script si une commande échoue. J'ai essayé :

my_command && (echo 'my_command failed; exit)

mais cela ne fonctionne pas. Il continue à exécuter les instructions qui suivent cette ligne dans le script. J'utilise Ubuntu et bash.

6 votes

Le guillemet non fermé était-il censé constituer une erreur de syntaxe entraînant un échec ou une sortie ? Dans le cas contraire, vous devriez fermer le guillemet dans votre exemple.

550voto

codaddict Points 154968

Essayez :

my_command || { echo 'my_command failed' ; exit 1; }

Quatre changements :

  • Changement && à ||
  • Utilisez { } à la place de ( )
  • Présentez ; après exit et
  • espaces après { et avant }

Puisque vous souhaitez imprimer le message et sortir uniquement lorsque la commande échoue (sortie avec une valeur non nulle), vous avez besoin d'un fichier de type || pas un && .

cmd1 && cmd2

fonctionnera cmd2 quand cmd1 réussit(valeur de sortie 0 ). Où comme

cmd1 || cmd2

fonctionnera cmd2 quand cmd1 échoue (valeur de sortie non nulle).

Utilisation de ( ) fait en sorte que la commande qu'ils contiennent soit exécutée dans un sous-coquille et appeler un exit à partir de là, vous quittez le sous-shell et non votre shell d'origine, l'exécution continue donc dans votre shell d'origine.

Pour surmonter cette difficulté, utilisez { }

Les deux derniers changements sont requis par bash.

7 votes

Il semble bien qu'elle soit "inversée". Si une fonction "réussit", elle renvoie 0 et si elle "échoue", elle renvoie un résultat différent de zéro. On peut donc s'attendre à ce que && soit évalué lorsque la première moitié renvoie un résultat différent de zéro. Cela ne signifie pas que la réponse ci-dessus est incorrecte - non, elle est correcte. && et || dans scripts fonctionnent en fonction du succès et non de la valeur de retour.

12 votes

Cela semble inversé, mais lisez-le et cela a du sens : "exécuter cette commande (avec succès)" OU "afficher cette erreur et quitter"

3 votes

La logique derrière cela est que le langage utilise l'évaluation des courts-circuits (SCE). Avec SCE, si l'expression est de la forme "p OR q", et que p est évalué comme vrai, alors il n'y a aucune raison de regarder q. Si l'expression est de la forme "p AND q", et que p est évalué comme faux, il n'y a aucune raison de regarder q. La raison est double : 1) c'est plus rapide, pour des raisons évidentes et 2) cela évite certains types d'erreurs (par exemple : "if x!=0 AND 10/x > 5" plantera s'il n'y a pas de SCE). La possibilité de l'utiliser en ligne de commande comme ceci est un heureux effet secondaire.

170voto

Daenyth Points 11297

Les autres réponses ont bien couvert la question directe, mais vous pourriez aussi être intéressé par l'utilisation de set -e . Avec cela, toute commande qui échoue (en dehors de contextes spécifiques tels que if tests) provoquera l'abandon du script. Pour certains script, c'est très utile.

6 votes

Malheureusement, c'est aussi très dangereux. set -e a un ensemble de règles longues et obscures qui déterminent quand cela fonctionne et quand cela ne fonctionne pas. (Si quelqu'un dirige if yourfunction; then ... alors set -e ne fera jamais feu à l'intérieur yourfunction ou tout ce qu'il appelle, car ce code est considéré comme "vérifié"). Voir la section des exercices de BashFAQ #105 , discutant de ce problème et d'autres pièges (dont certains ne s'appliquent qu'à des versions spécifiques de l'interpréteur de commandes, vous devez donc être sûr de tester contre chaque version qui pourrait être utilisée pour exécuter votre script).

116voto

damienfrancois Points 7545

Si vous voulez ce comportement pour toutes les commandes de votre script, ajoutez simplement

set -e 
set -o pipefail

au début du script. Cette paire d'options indique à l'interpréteur bash de quitter chaque fois qu'une commande revient avec un code de sortie non nul. (Pour plus de détails sur la raison pour laquelle pipefail est nécessaire, voir http://petereisentraut.blogspot.com/2010/11/pipefail.html )

Cela ne vous permet pas d'imprimer un message de sortie, cependant.

13 votes

Vous pouvez exécuter des commandes à la sortie en utilisant l'option trap commande intégrée de bash.

1 votes

C'est la réponse à la question X-Y.

8 votes

Il pourrait être intéressant d'expliquer ce que les commandes font indépendamment plutôt que la paire. D'autant plus que set -o pipefail n'est peut-être pas le comportement souhaité. Merci quand même de l'avoir signalé !

82voto

Alex Howansky Points 16820

Notez également que l'état de sortie de chaque commande est stocké dans la variable shell $ ?, que vous pouvez vérifier immédiatement après l'exécution de la commande. Un état non nul indique un échec :

my_command
if [ $? -eq 0 ]
then
    echo "it worked"
else
    echo "it failed"
fi

12 votes

Cela peut être remplacé par if my_command, il n'est pas nécessaire d'utiliser la commande test ici.

7 votes

+1 parce que je pense que vous ne devriez pas être puni pour avoir listé cette alternative - elle devrait être sur la table - bien qu'elle soit un peu moche et, selon mon expérience, trop facile de lancer une autre commande entre les deux sans remarquer la nature du test (peut-être que je suis juste stupide).

1 votes

@BartSas Si la commande est longue, il est préférable de la mettre sur sa propre ligne. Cela rend le script plus lisible.

17voto

Benoit Points 35553

Fourni my_command est conçu de manière canonique, c'est-à-dire renvoie 0 en cas de succès, alors && est exactement le contraire de ce que vous voulez. Vous voulez || .

Notez également que ( ne me semble pas correct dans bash, mais je ne peux pas essayer d'où je suis. Dites-moi.

my_command || {
    echo 'my_command failed' ;
    exit 1; 
}

0 votes

IIRC, vous avez besoin de points-virgules après chacune des lignes à l'intérieur de {}.

11 votes

@Alex : pas s'ils sont sur une ligne séparée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X