Cómo activar un error usando el comando Trap

13

Estoy usando Ubuntu 12.04.2. Estoy tratando de usar el comando "trap" para capturar anormales o errores en mi script de shell, pero también estoy tratando de activar manualmente la salida "Error".

He intentado salir 1, pero no activará la señal de "Error".

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

¿No está seguro de cómo activar manualmente la señal de salida "Error"?

payaso
fuente

Respuestas:

20

la ERRtrampa no es ejecutar código cuando el shell mismo sale con un código de error distinto de cero, sino cuando cualquier comando ejecutado por ese shell que no es parte de una condición (como en if cmd..., o cmd || ......) sale con un código distinto de cero estado de salida (las mismas condiciones que lo que hace set -eque salga del shell).

Si desea ejecutar código al salir del shell con un estado de salida distinto de cero, debe agregar una trampa en su EXITlugar y verificar $?allí:

trap '[ "$?" -eq 0 ] || echo hi' EXIT

Sin embargo, tenga en cuenta que en una señal atrapada, se ejecutarán tanto la captura de señal como la captura EXIT, por lo que es posible que desee hacerlo como:

unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
  ret=$?
  if [ -n "$killed_by" ]; then
    echo >&2 "Ouch! Killed by $killed_by"
    exit 1
  elif [ "$ret" -ne 0 ]; then
    echo >&2 "Died with error code $ret"
  fi' EXIT

O para usar el estado de salida como $((signum + 128))en las señales:

for sig in INT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT

Sin embargo, tenga en cuenta que salir normalmente de SIGINT o SIGQUIT tiene posibles efectos secundarios molestos cuando su proceso principal es un shell como el bashque implementa el manejo de espera y salida cooperativa de la interrupción de terminal. Por lo tanto, es posible que desee asegurarse de suicidarse con la misma señal para informar a sus padres que realmente fue interrumpido, y que debería considerar salir también si recibió un SIGINT / SIGQUIT.

unset killed_by
for sig in INT QUIT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
  if [ -n "$killed_by" ]; then
    trap - "$killed_by" # reset handler
    # ulimit -c 0 # possibly disable core dumps
    kill -s "$killed_by" "$$"
  else
    exec "$ret"
  fi' EXIT

Si desea ERRque se dispare la trampa, simplemente ejecute un comando con un estado de salida distinto de cero como falseo test.

Stéphane Chazelas
fuente
6

Uso de retorno, no de salida, para establecer el estado de salida de una función (si la función cae a través sin un retorno, el estado es el de la última instrucción ejecutada.) Si sustituye returnpor exiten el ejemplo de la cuestión, que funcionará como Creo que pretendía: la trampa se activará en la pseudo-señal ERR y se imprimirá 'hola'. Para consideraciones adicionales, intente esto:

#!/bin/bash

func()
{
    echo 'in func'
    return 99
    echo 'still in func'
}

trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'

Puede probar varias modificaciones, como devolver 0, comentar la trampa ERR, no cancelar la trampa EXIT dentro del controlador ERR, no salir del controlador ERR o eliminar la devolución y ponerla falsecomo la última declaración en func.

sdenham
fuente