
Estou usando uma armadilha ERR para detectar qualquer erro em meu script bash e exibir o que aconteceu no log. (semelhante a esta pergunta:Trap, ERR e eco da linha de erro) Funciona conforme o esperado. O único problema é que em algum ponto do meu script espera-se que um código de saída! = 0 aconteça. Como posso fazer com que a armadilha não seja acionada nesta situação?
Aqui está um código:
err_report() {
echo "errexit on line $(caller)" | tee -a $LOGFILE 1>&2
}
trap err_report ERR
Mais tarde no script:
<some command which occasionally will return a non-zero exit code>
if [ $? -eq 0 ]; then
<handle stuff>
fi
Toda vez que o comando retorna diferente de zero, minha armadilha é acionada. Posso evitar isso apenas para esta parte do código?
Eu verifiquei esta pergunta:Comportamento correto das armadilhas EXIT e ERR ao usar `set -eu` mas não estou realmente entendendo como aplicá-lo ao meu caso - se é que é aplicável.
Responder1
Um ERR
trap
não será acionado se um código de erro for imediatamente "detectado", o que significa que vocêpodeuse if
instruções e outros enfeites sem ter que ativar e desativar a captura de erros o tempo todo. No entanto, vocênão podeuse a verificação $?
para controle de fluxo, porque conforme chegar a essa verificação, você já (pode) ter o erro não detectado.
Se você tem um comando, espera falhar - e vocênãodeseja que essas falhas acionem o trap
, você simplesmente precisa detectar a falha. Envolvê-los em uma if
declaração é desajeitado e detalhado, mas esta abreviação funciona bem:
/bin/false || : # will not trigger an ERR trap
No entanto, se você quiser fazer coisas quando um comando falhar, if
tudo bem aqui:
if ! /bin/false; then
echo "this was not caught by the trap!"
fi
Ou, alternativamente, else
também capturará o estado de erro:
if /bin/false; then
: # dead code
else
echo "this was not caught by the trap!"
fi
Em suma, set -e
e trap "command" ERR
só desarma se houver uma condição de erro que não seja imediata e intrinsecamente contabilizada.
Responder2
Você pode ativar/desativar a ERR
interceptação durante partes do seu código, conforme necessário.
#!/bin/bash
err_report() {
echo "errexit on line $(caller)"
}
trap err_report ERR
trap - ERR # disable ERR trap
false
if [ $? -eq 0 ]; then
printf "OK\n"
else
printf "FAIL\n" # prints FAIL
fi
trap err_report ERR # enable ERR trap
false # prints errexit on line 14
Responder3
Acho que muitas vezes quero evitar a armadilha ERR, mas também não quero descartar o código de retorno da minha função. Então o padrão que uso é este:
RC=0
some_function || RC=$?
Então eu faço o que preciso fazer com RC.
Responder4
A ERR
armadilha obedece às mesmas regras do set -e
, ou seja, não tem efeito nos comandos que são usados como condições. Então,
trap "echo error" ERR
false # this should trigger the trap
if ! false; then # this shouldn't
echo handle stuff
fi
Lembre-se de que o comando na if
condição pode serqualquercomando, não precisa ser [ .. ]
. Portanto, se você deseja apenas uma avaliação verdadeiro/falso do status de saída de um comando, basta usá-lo diretamente na if
condição.
Se você precisar salvar o código de saídaeevite a ERR
armadilha, você precisará fazer algo como
somecmd && :; ret=$?
Aqui, o &&
irá esmagar a ERR
armadilha, mas como só é executado se o código de saída for zero, saberemos que o código de saída é o mesmo depois de :
.
Você pode querer verificarBashFAQ 105: Por que set -e (ou set -o errexit ou trap ERR) não faz o que eu esperava?