web-dev-qa-db-fra.com

Comment quitter si une commande échoue?

Je suis un noob en script-shell. Je souhaite 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 à exécuter les instructions en suivant cette ligne dans le script. J'utilise Ubuntu et bash.

183
user459246

Essayer:

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

Quatre changements:

  • Remplacez && par ||
  • Utilisez { } à la place de ( )
  • Introduisez ; après exit et
  • espaces après { et avant }

Puisque vous voulez imprimer le message et ne quitter que lorsque la commande échoue (les commandes avec une valeur différente de zéro), vous avez besoin d'un || et non d'un &&.

cmd1 && cmd2

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

cmd1 || cmd2

exécutera cmd2 lorsque cmd1 échoue (valeur de sortie non nulle).

En utilisant ( ), la commande à l'intérieur s'exécute dans un sous-shell et en appelant un exit à partir de là, vous quittez le sous-shell et non votre shell d'origine; l'exécution se poursuit donc dans votre shell d'origine.

Pour surmonter cela, utilisez { }

Les deux derniers changements sont requis par bash.

346
codaddict

Les autres réponses ont bien couvert la question directe, mais vous pouvez également être intéressé par 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 scripts, c'est très utile.

118
Daenyth

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

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

58
damienfrancois

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 statut différent de zéro indique un échec:

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

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."

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

13
Grant Birchmeier

Si my_command est conçu de manière canon, ie renvoie 0 s'il réussit, alors && est exactement le contraire de ce que vous voulez. Vous voulez ||.

Notez également que ( ne me semble pas correct en Bash, mais je ne peux pas essayer d’où je suis. Dîtes-moi.

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

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

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

Ceci n’imprimera toutefois aucun message d’erreur supplémentaire. Mais dans certains cas, l'erreur sera quand même imprimée par la commande ayant échoué.

4
alexpirine

Le shell intégré trap permet de capturer les signaux et d’autres conditions utiles, y compris l’échec de l’exécution de la commande (c’est-à-dire un état de retour non nul). Donc, si vous ne voulez pas tester explicitement le statut de retour de chaque commande, vous pouvez dire trap "your Shell code" ERR et le code Shell sera exécuté chaque fois qu'une commande retournera un statut différent de zéro. Par exemple:

trap "echo script failed; exit 1" ERR

Notez que, comme dans d'autres cas de capture de commandes ayant échoué, les pipelines nécessitent un traitement spécial; ce qui précède n'acceptera pas false | true.

3
kozel

Les fonctions suivantes ne font écho aux erreurs qu'en cas d'échec d'une commande:

silently () {
    label="${1}"
    command="${2}"
    error=$(eval "${command}" 2>&1 >"/dev/null")

    if [ ${?} -ne 0 ]; then
        echo "${label}: ${error}" >&2
        exit 1
    fi
}
0