
Я использую ловушку 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) не делает то, что я ожидал?