bash - programas - scripts linux ejercicios resueltos
Salir del script de shell según el código de salida del proceso (9)
Tengo un script de shell que ejecuta una serie de 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?
" set -e " es probablemente la forma más fácil de hacer esto. Simplemente ponga eso antes de cualquier comando en su programa.
En bash esto es fácil, simplemente unirlos con &&:
command1 && command2 && command3
También puedes usar el anidado si construyes:
if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi
Si desea trabajar con $ ?, necesitará verificarlo después de cada comando, ¿desde $? se actualiza después de que cada comando sale. Esto significa que si ejecuta una tubería, solo obtendrá el código de salida del último proceso en la tubería.
Otro enfoque es hacer esto:
set -e
set -o pipefail
Si coloca esto en la parte superior del script de shell, parece que bash se hará cargo de esto por usted. Como se anotó en un póster anterior, "set -e" hará que bash salga con un error en cualquier comando simple. "set -o pipefail" causará que bash se cierre con un error en cualquier comando en una tubería también.
Vea here o here para un poco más de discusión sobre este problema. Here está la sección del manual de bash en el set incorporado.
Si solo llama a exit en el bash sin parámetros, devolverá el código de salida del último comando. Combinado con OR, 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 $ ?.
para el 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;
}
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
¿Cómo obtengo el código de salida de
cmd1encmd1|cmd2En primer lugar, tenga en cuenta que el código de salida de
cmd1podría ser distinto de cero y aún no significa un error. Esto sucede, por ejemplo, encmd | head -1puede observar un estado de salida de 141 (o 269 con ksh93) de
cmd1, pero es porquecmdfue interrumpido por una señal SIGPIPE cuando lahead -1terminó después de haber leído una línea.Para conocer el estado de salida de los elementos de una tubería
cmd1 | cmd2 | cmd3cmd1 | cmd2 | cmd3a. con zsh:
Los códigos de salida se proporcionan en la matriz especial pipestatus.
cmd1código de salida decmd1está en$pipestatus[1], el código de salida decmd3en$pipestatus[3], por lo que$?siempre es lo mismo que$pipestatus[-1].segundo. con bash
Los códigos de salida se proporcionan en la
PIPESTATUSespecialPIPESTATUS.cmd1código de salida decmd1está en${PIPESTATUS[0]}, el código de salida decmd3en${PIPESTATUS[2]}, por lo que$?siempre es lo mismo que${PIPESTATUS: -1}....
Para más detalles ver el siguiente http://cfaj.freeshell.org/shell/cus-faq-2.html#11 .
Después de cada comando, el código de salida se puede encontrar en el $? variable para que tengas algo como:
ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
Tienes que tener cuidado con los comandos canalizados desde el $? solo le da el código de retorno del último elemento en el conducto, 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 tubería realmente funciona, devolviendo 0).
El shell bash realidad proporciona una matriz que puede ayudar en ese caso, que es PIPESTATUS . Esta matriz tiene un elemento para cada uno de los componentes de canalización, al que puede acceder individualmente como ${PIPESTATUS[0]} :
pax> false | true ; echo ${PIPESTATUS[0]}
1
Tenga en cuenta que esto le permite obtener el resultado del comando false , no toda la canalización. También puede hacer que la lista completa se procese como mejor le parezca:
pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1
Si quisiera obtener el código de error más grande de una tubería, 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 de PIPESTATUS a su vez, almacenándolo en rc si era mayor que el valor de rc anterior.
#
#------------------------------------------------------------------------------
# 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
[ $? -eq 0 ] || exit $?; # exit for none-zero return code