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
cmd1
encmd1|cmd2
En primer lugar, tenga en cuenta que el código de salida de
cmd1
podría ser distinto de cero y aún no significa un error. Esto sucede, por ejemplo, encmd | head -1
puede observar un estado de salida de 141 (o 269 con ksh93) de
cmd1
, pero es porquecmd
fue interrumpido por una señal SIGPIPE cuando lahead -1
terminó 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
cmd1 | cmd2 | cmd3
a. con zsh:
Los códigos de salida se proporcionan en la matriz especial pipestatus.
cmd1
código de salida decmd1
está en$pipestatus[1]
, el código de salida decmd3
en$pipestatus[3]
, por lo que$?
siempre es lo mismo que$pipestatus[-1]
.segundo. con bash
Los códigos de salida se proporcionan en la
PIPESTATUS
especialPIPESTATUS
.cmd1
código de salida decmd1
está en${PIPESTATUS[0]}
, el código de salida decmd3
en${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