Exit Shell Script Basado en el Código de Salida del Proceso


Tengo un script de shell que ejecuta varios comandos. ¿Cómo hago que el script de shell salga si alguno de los comandos sale con un código de salida distinto de cero?

 339
Author: Cerin, 2008-09-18

9 answers

Después de cada comando, el código de salida se puede encontrar en la variable $? por lo que tendría algo como:

ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi

Debe tener cuidado con los comandos canalizados ya que el $? solo le da el código de retorno del último elemento en la tubería, por lo que, en el código:

ls -al file.ext | sed 's/^/xx: /"

No devolverá un código de error si el archivo no existe (ya que la parte sed de la canalización realmente funciona, devolviendo 0).

El shell bash en realidad proporciona una matriz que puede ayudar en ese caso, ese ser PIPESTATUS. Esta matriz tiene un elemento para cada uno de los componentes de la canalización, al que puede acceder individualmente como ${PIPESTATUS[0]}:

pax> false | true ; echo ${PIPESTATUS[0]}
1

Tenga en cuenta que esto le está obteniendo el resultado del comando false, no toda la canalización. También puede obtener toda la lista para procesar como mejor le parezca:

pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1

Si desea obtener el código de error más grande de una canalización, podría usar algo como:

true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc

Esto pasa por cada uno de los elementos PIPESTATUS a su vez, almacenándolo en rc si era mayor que el anterior rc valor.

 433
Author: paxdiablo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-07 01:24:37

Si quieres trabajar con $?, tendrá que comprobarlo después de cada comando, ya que?? se actualiza después de que sale cada comando. Esto significa que si ejecuta una canalización, solo obtendrá el código de salida del último proceso de la canalización.

Otro enfoque es hacer esto:

set -e
set -o pipefail

Si pones esto en la parte superior del script de shell, parece que bash se encargará de esto por ti. Como señaló un póster anterior, "set-e" hará que bash salga con un error en cualquier comando simple. "set-o pipefail" hará que bash salga con un error en cualquier comando de una canalización también.

Ver aquío aquí para un poco más de discusión sobre este problema. Aquí está la sección manual de bash en el conjunto incorporado.

 207
Author: Jeff Hill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 06:20:55

"set -e" es probablemente la forma más fácil de hacer esto. Simplemente pon eso antes de cualquier comando en tu programa.

 47
Author: Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 06:09:55

Si solo llama a exit en el bash sin parámetros, devolverá el código de salida del último comando. Combinado con O el bash solo debe invocar exit, si el comando anterior falla. Pero no he probado esto.

command1 || exit;
command2 || exit;

El Bash también almacenará el código de salida del último comando en la variable $?.

 27
Author: Arvodan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 06:11:37
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
 23
Author: chemila,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-26 23:15:24

Http://cfaj.freeshell.org/shell/cus-faq-2.html#11

  1. Cómo obtengo el código de salida de cmd1 en cmd1|cmd2

    Primero, tenga en cuenta que cmd1 el código de salida podría ser distinto de cero y aún no significa un error. Esto sucede por ejemplo en

    cmd | head -1
    

    Es posible que observe un estado de salida 141 (o 269 con ksh93) de cmd1, pero es porque cmd fue interrumpido por una señal SIGPIPE cuando head -1 terminado después de haber leído una línea.

    Para conocer el estado de salida de los elementos de una tubería cmd1 | cmd2 | cmd3

    A. con zsh: {[24]]}

    Los códigos de salida se proporcionan en el array especial pipestatus. cmd1 el código de salida está en $pipestatus[1], cmd3 código de salida en $pipestatus[3], de modo que $? es siempre lo mismo que $pipestatus[-1].

    B. con bash:

    Los códigos de salida se proporcionan en el array especial PIPESTATUS. cmd1 el código de salida está en ${PIPESTATUS[0]}, cmd3 código de salida en ${PIPESTATUS[2]}, de modo que $? es siempre lo mismo que ${PIPESTATUS: -1}.

    ...

    Para más para más detalles, véase el siguiente enlace .

 20
Author: gatoatigrado,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-17 19:37:11

Para bash:

# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;

#
# ... the rest of the script goes here
#  

function catch_errors() {
   # do whatever on errors
   # 
   #
   echo "script aborted, because of errors";
   exit 0;
}
 19
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 06:18:53

En bash esto es fácil, simplemente atarlos con&&:

command1 && command2 && command3

También puedes usar la construcción if anidada:

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi
 8
Author: Martin W,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 06:08:32
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
    cmd="$@" ;

    doLog "DEBUG running cmd or exit: \"$cmd\""
    msg=$($cmd 2>&1)
    export exit_code=$?

    # if occured during the execution exit with error
    error_msg="Failed to run the command:
        \"$cmd\" with the output:
        \"$msg\" !!!"

    if [ $exit_code -ne 0 ] ; then
        doLog "ERROR $msg"
        doLog "FATAL $msg"
        doExit "$exit_code" "$error_msg"
    else
        #if no errors occured just log the message
        doLog "DEBUG : cmdoutput : \"$msg\""
        doLog "INFO  $msg"
    fi

}
#eof func doRunCmdOrExit
 4
Author: Yordan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-25 09:16:40