Как предотвратить срабатывание ловушки ERR при выполнении одной команды?

Как предотвратить срабатывание ловушки ERR при выполнении одной команды?

Я использую ловушку ERR для обнаружения любых ошибок в моем скрипте bash и вывода произошедшего в журнал. (похоже на этот вопрос:Trap, ERR и повтор строки с ошибкой) Работает как и ожидалось. Единственная проблема в том, что в какой-то момент в моем скрипте ожидается код выхода !=0. Как сделать так, чтобы ловушка не срабатывала в этой ситуации?

Вот код:

err_report() {
    echo "errexit on line $(caller)" | tee -a $LOGFILE 1>&2
}

trap err_report ERR

Далее в сценарии:

<some command which occasionally will return a non-zero exit code>

if [ $? -eq 0 ]; then
    <handle stuff>
fi

Каждый раз, когда команда возвращает ненулевое значение, срабатывает моя ловушка. Можно ли избежать этого только для этой части кода?

Я проверил этот вопрос:Корректное поведение ловушек EXIT и ERR при использовании `set -eu` но я не совсем понимаю, как это применить к моему случаю — если это вообще применимо.

решение1

Не сработает ERR trap, если код ошибки будет немедленно «перехвачен», что означает, что выможетиспользовать ifоператоры и т. д. без необходимости постоянно включать и выключать отлавливание ошибок. Однако выне могуиспользуйте проверку $?для управления потоком, потому что к моменту этой проверки у вас уже (может) быть неперехваченная ошибка.

Если у вас есть команда, которую вы ожидаете провалить, и вынехотите, чтобы эти сбои запускали trap, вам просто нужно поймать сбой. Оборачивать их в ifоператоре неуклюже и многословно, но это сокращение работает хорошо:

/bin/false || :  # will not trigger an ERR trap

Однако, если вы хотите что-то сделать, когда команда не выполняется, ifвот что подойдет:

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

Или, в качестве альтернативы, elseтакже будет перехватывать состояние ошибки:

if /bin/false; then
    : # dead code
else
    echo "this was not caught by the trap!"
fi

В общем, set -eи trap "command" ERRсрабатывают только в том случае, если возникает состояние ошибки, которое не может быть немедленно и по сути учтено.

решение2

При необходимости вы можете включать/отключать ERRловушку во время выполнения определенных частей кода.

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

решение3

Я обнаружил, что мне часто хочется избежать ловушки ERR, но я также не хочу отбрасывать код возврата моей функции. Поэтому я использую следующий шаблон:

RC=0
some_function || RC=$?

Затем я делаю все, что мне нужно, с помощью RC.

решение4

Ловушка ERRподчиняется тем же правилам set -e, что и , то есть она не оказывает влияния на команды, которые используются в качестве условий. Итак,

trap "echo error" ERR
false                     # this should trigger the trap
if ! false; then          # this shouldn't
     echo handle stuff
fi

Помните, что команда в ifусловии может бытьлюбойcommand, это не обязательно должно быть [ .. ]. Так что, если вам нужна только оценка true/false статуса выхода команды, просто используйте ее непосредственно в ifусловии.

Если вам нужно сохранить код выходаиЧтобы избежать ERRловушки, вам нужно сделать что-то вроде

somecmd && :; ret=$?

В данном случае ловушка &&будет устранена ERR, но поскольку она запускается только в том случае, если код выхода равен нулю, мы будем знать, что код выхода тот же самый после :.

Вы можете проверитьBashFAQ 105: Почему set -e (или set -o errexit, или trap ERR) не делает то, что я ожидал?

Связанный контент