Como evitar que um comando acione a armadilha ERR?

Como evitar que um comando acione a armadilha ERR?

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 trapnão será acionado se um código de erro for imediatamente "detectado", o que significa que vocêpodeuse ifinstruçõ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 ifdeclaraçã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, iftudo bem aqui:

if ! /bin/false; then
    echo "this was not caught by the trap!"
fi

Ou, alternativamente, elsetambé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 -ee trap "command" ERRsó desarma se houver uma condição de erro que não seja imediata e intrinsecamente contabilizada.

Responder2

Você pode ativar/desativar a ERRinterceptaçã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 ERRarmadilha 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 ifcondiçã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 ifcondição.

Se você precisar salvar o código de saídaeevite a ERRarmadilha, você precisará fazer algo como

somecmd && :; ret=$?

Aqui, o &&irá esmagar a ERRarmadilha, 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?

informação relacionada