Salir de un script en caso de error

141

Estoy creando un script de Shell que tiene una iffunción como esta:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables
fi

...

Quiero que la ejecución del script finalice después de mostrar el mensaje de error. ¿Como puedo hacer esto?

Nathan Campos
fuente

Respuestas:

137

¿Está buscando exit?

Esta es la mejor guía de bash. http://tldp.org/LDP/abs/html/

En contexto:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables 1>&2
    exit 1 # terminate and indicate error
fi

...
Byron Whitlock
fuente
55
Si te gusta el ABS, te encantarán las BashGuide , BashFAQ y BashPitfalls .
Pausado hasta nuevo aviso.
¡Esos enlaces Bash son IMPRESIONANTES! BashFAQ estaría mejor posicionado como BashRecipes.
Pete Alvin
337

Si coloca set -euna secuencia de comandos, la secuencia de comandos finalizará tan pronto como falle cualquier comando dentro de ella (es decir, tan pronto como cualquier comando devuelva un estado distinto de cero). Esto no le permite escribir su propio mensaje, pero a menudo los mensajes del comando que falla son suficientes.

La ventaja de este enfoque es que es automático: no corre el riesgo de olvidarse de lidiar con un caso de error.

Los comandos cuyo estado es probado por un condicional (como if, &&o ||) no terminan el script (de lo contrario, el condicional no tendría sentido). Un modismo para el comando ocasional cuyo fracaso no importa es command-that-may-fail || true. También puede set -edesactivar una parte del script con set +e.

Gilles 'SO- deja de ser malvado'
fuente
3
Según mywiki.wooledge.org/BashFAQ/105 , esta característica tiene un historial de ser oscura y complicada en su determinación de qué códigos de error de comandos provocan una salida automática. Además, "las reglas cambian de una versión de Bash a otra, ya que Bash intenta rastrear la definición POSIX extremadamente resbaladiza de esta 'característica'". Estoy de acuerdo con @Dennis Williamson y la respuesta aceptada de stackoverflow.com/questions/19622198/… - use trap 'error_handler' ERR. ¡Incluso si es una trampa!
Bondolin
3
a menudo, usar la -xbandera con la -ebandera es suficiente para saber dónde está su programa al salir. Eso implica que el usuario del script también es el desarrollador.
Alex
Agradable, pero creo que el OP necesitaba salir del script desde una excepción autodefinida.
vdegenne
42

Si desea poder manejar un error en lugar de salir a ciegas, en lugar de usar set -e, use a trapen la ERRpseudo señal.

#!/bin/bash
f () {
    errorCode=$? # save the exit code as the first thing done in the trap function
    echo "error $errorCode"
    echo "the command executing at the time of the error was"
    echo "$BASH_COMMAND"
    echo "on line ${BASH_LINENO[0]}"
    # do some error handling, cleanup, logging, notification
    # $BASH_COMMAND contains the command that was being executed at the time of the trap
    # ${BASH_LINENO[0]} contains the line number in the script of that command
    # exit the script or return to try again, etc.
    exit $errorCode  # or use some other value or do return instead
}
trap f ERR
# do some stuff
false # returns 1 so it triggers the trap
# maybe do some other stuff

Se pueden configurar otras trampas para manejar otras señales, incluidas las señales habituales de Unix más las otras pseudo señales RETURNy Bash DEBUG.

Pausado hasta nuevo aviso.
fuente
8

Aquí está la forma de hacerlo:

#!/bin/sh

abort()
{
    echo >&2 '
***************
*** ABORTED ***
***************
'
    echo "An error occurred. Exiting..." >&2
    exit 1
}

trap 'abort' 0

set -e

# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0

echo >&2 '
************
*** DONE *** 
************
'
supercobra
fuente
¿Por qué el mensaje HECHO a stderr?
MattBianco
1
Esta es una práctica común para que pueda canalizar la salida de su script a stdout para que otro proceso pueda obtenerlo sin tener los mensajes de información en el medio.
supercobra
2
Probablemente sea una práctica igualmente común tratar cualquier cosa en stderr como una indicación de problemas.
MattBianco
1
En el pasado, 'set -e' siempre ha funcionado para mí, pero esta noche me encontré con una situación en una imagen de Alpine Linux Docker en la que no tuvo ningún efecto ... Esta solución funcionó para mí y me devolvió a la tarea en cuestión. Muy apreciado.
sintetizadorpatel
@supercobra ¿Práctica común? ¿Dónde?
Thorbjørn Ravn Andersen
-8

exit 1es todo lo que necesitas. El 1es un código de retorno, por lo que puede cambiarlo si quiere, por ejemplo, 1significar una ejecución exitosa y -1significar una falla o algo así.

DGH
fuente
13
En Unix, el éxito siempre es 0. Esto puede ayudar cuando se usa testo &&o ||.
mouviciel
55
Para ampliar el comentario de Mouviciel: en los scripts de shell, 0 siempre significa éxito y 1 a 255 significa fracaso. -1 está fuera de rango (y a menudo tendrá el mismo efecto que 255, por lo que una falla como 1).
Gilles 'SO- deja de ser malvado'
@mouviciel, @Gilles: Gracias por la información adicional. Ha pasado un tiempo desde que traté con bash.
DGH
Este es un mal ejemplo del uso del código de retorno, de lo contrario sería una gran respuesta.
Brad Koch
1
Además de recomendar incorrectamente 1 para el éxito, -1 no es posible (los códigos de salida no están firmados).
tripleee