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 ça ne marche pas. Il continue d’exécuter les instructions suivant cette ligne dans le script. J’utilise Ubuntu et bash.

Essayer:

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

Quatre changements:

  • Change && à ||
  • Utilisez { } à la place de ( )
  • Introduire après la exit et
  • espaces après { et avant }

Comme vous voulez imprimer le message et quitter uniquement lorsque la commande échoue (se termine avec une valeur différente de zéro), vous avez besoin d’un || pas un && .

 cmd1 && cmd2 

exécutera cmd2 lorsque cmd1 réussit (valeur de sortie 0 ). Tandis que

 cmd1 || cmd2 

exécutera cmd2 lorsque cmd1 échoue (valeur de sortie différente de zéro).

Utiliser ( ) rend la commande à l’intérieur d’eux exécutée dans un sous-shell et appeler une exit partir de là vous fait quitter le sous-shell et non votre shell d’origine, donc l’exécution continue dans votre shell d’origine.

Pour surmonter cette utilisation { }

Les deux dernières modifications sont requirejses par bash.

Les autres réponses ont bien couvert la question directe, mais vous pouvez également être intéressé par l’utilisation de set -e . Avec cela, toute commande qui échoue (en dehors de contextes spécifiques comme les tests) provoquera l’interruption du script. Pour certains scripts, c’est très utile.

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

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

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 retourne avec un code de sortie différent de zéro.

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

J’ai piraté l’idiome suivant:

 echo "Generating from IDL..." idlj -fclient -td java/src echo.idl if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi echo "Compiling classes..." javac *java if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi echo "Done." 

Précède chaque commande avec un écho informatif et suit chaque commande avec cette même
if [ $? -ne 0 ];... if [ $? -ne 0 ];... ligne. (Bien sûr, vous pouvez modifier ce message d’erreur si vous le souhaitez.)

Si my_command est conçu de manière canonique, c. -à- d. my_command 0 lorsqu’il réussit, alors && est exactement le contraire de ce que vous voulez. Vous voulez || .

Notez également que ( ne me semble pas juste en bash, mais je ne peux pas essayer d’où je suis. Dites-moi.

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

Le shell trap intégré permet de capturer des signaux et d’autres conditions utiles, y compris l’échec de l’exécution de la commande (c.-à-d. Un état de retour non nul). Donc, si vous ne voulez pas tester explicitement le statut de retour de chaque commande, vous pouvez dire que le trap "your shell code" ERR et le code shell seront exécutés chaque fois qu’une commande retourne un statut non nul. Par exemple:

trap "echo script failed; exit 1" ERR

Notez que, comme pour les autres cas de capture de commandes ayant échoué, les pipelines nécessitent un traitement spécial; ce qui précède n’attrapera pas de false | true false | true

Pour les erreurs de vérification de vos commandes:

 execute [INVOKING-FUNCTION] [COMMAND] 

 execute () { error=$($2 2>&1 >/dev/null) if [ $? -ne 0 ]; then echo "$1: $error" exit 1 fi } 

Inspiré de la fabrication allégée:

  • Rendre les erreurs impossibles à concevoir
  • Faire les étapes le plus petit
  • Terminer les articles un par un
  • Rendez-le évident à tous

Vous pouvez également utiliser, si vous souhaitez conserver le statut d’erreur de sortie, un fichier lisible avec une commande par ligne:

 my_command1 || exit $? my_command2 || exit $? 

Ceci, cependant, n’imprimera aucun message d’erreur supplémentaire. Mais dans certains cas, l’erreur sera imprimée par la commande en échec.