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.
Essayer:
my_command || { echo 'my_command failed' ; exit 1; }
Quatre changements:
&&
par ||
{ }
à la place de ( )
;
après exit
et{
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.
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.
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.
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
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êmeif [ $? -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 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;
}
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é.
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
.
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
}