Como disparar erro usando o comando Trap

13

Estou usando o Ubuntu 12.04.2. Eu estou tentando usar o comando "trap" para capturar anormal ou erro no meu script de shell, mas também estou tentando disparar manualmente a saída "Erro".

Eu tentei a saída 1, mas ela não acionará o sinal "Erro".

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

Não sabe como disparar manualmente o sinal de saída "Erro"?

    
por forestclown 17.06.2013 / 06:21

2 respostas

19

o ERR trap não é para executar o código quando o próprio shell sai com um código de erro diferente de zero, mas quando qualquer comando executado pelo shell que não faz parte de uma condição (como em if cmd... ou cmd || ... ...) sai com um status de saída diferente de zero (as mesmas condições que fazem com que set -e saia do shell).

Se você quiser executar o código na saída do shell com status de saída diferente de zero, adicione uma interceptação em EXIT e verifique $? there:

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

Note, entretanto, que após um sinal aprisionado, tanto o sinal trap como o EXIT serão executados, então você pode querer fazer assim:

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

Ou para usar o status de saída como $((signum + 128)) nos sinais:

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

Note, entretanto, que sair normalmente no SIGINT ou SIGQUIT tem efeitos colaterais potencialmente irritantes quando o processo pai é um shell como bash que implementa o espera e saída cooperativa manuseio da interrupção do terminal. Então, você pode querer se certificar de se matar com o mesmo sinal para relatar ao seu pai que você foi de fato interrompido, e que ele deveria considerar sair de si mesmo também se ele recebeu um 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

Se você quiser que a armadilha ERR seja disparada, basta executar um comando com um status de saída diferente de zero, como false ou test .

    
por 17.06.2013 / 08:50
7

Use retorno, não saída, para definir o status ao sair de uma função (se a função passar sem retorno, o status é o da última instrução executada.) Se você substituir return por exit no exemplo da pergunta, ele funcionará como acho que você pretendia: a interceptação será ativada no pseudo-sinal ERR e 'oi' será impresso. Para considerações adicionais, tente isto:

#!/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'

Você pode tentar várias modificações, como retornar 0, comentar a interceptação ERR, não cancelar a interceptação EXIT no manipulador ERR, não sair do manipulador ERR ou remover o retorno e colocar false como a última instrução em func.

    
por 24.09.2014 / 21:54