I am using an ERR trap to catch any error in my bash script and output what happened to log. (similar to this question: Trap, ERR, and echoing the error line ) It works as expected. The only problem is, that at some point in my script an exitcode !=0 is expected to happen. How can I make the trap not trigger in this situation?
Here is some code:
err_report() {
echo "errexit on line $(caller)" | tee -a $LOGFILE 1>&2
}
trap err_report ERR
Then later in the script:
<some command which occasionally will return a non-zero exit code>
if [ $? -eq 0 ]; then
<handle stuff>
fi
Everytime the command returns non-zero my trap is triggered. Can I avoid this only for this part of the code?
I checked this question: Correct behavior of EXIT and ERR traps when using `set -eu` but I am not really getting how to apply it to my case - if at all aplicable.
4 Answers 4
An ERR
trap
will not trigger if an error code is immediately "caught", which means that you can use if
statements and whatnot without having to flip error trapping on and off all the time. However, you cannot use checking $?
for flow control, because as the time you get to that check, you already (may) have the uncaught error.
If you have a command you expect to fail -- and you do not want those failures to trigger the trap
, you simply have to catch the failure. Wrapping them in an if
statement is clunky and verbose, but this shorthand works nicely:
/bin/false || : # will not trigger an ERR trap
However, if you want to do things when a command fails, if
will be fine here:
if ! /bin/false; then
echo "this was not caught by the trap!"
fi
Or alternatively, else
will catch the error state also:
if /bin/false; then
: # dead code
else
echo "this was not caught by the trap!"
fi
In sum, set -e
and trap "command" ERR
only get tripped if there is an error condition which is not immediately and intrinsically accounted for.
-
Thanks for the reply. The "problem" is that the command above is not a simple command but rather a command chain with pipes which already takes up several lines. Is there a nice way to put this as
if
condition?masgo– masgo2018年05月31日 22:48:03 +00:00Commented May 31, 2018 at 22:48 -
2Just as with one command:
if ! foo | bar | baz | quux; then stuff; fi
.DopeGhoti– DopeGhoti2018年06月01日 15:59:06 +00:00Commented Jun 1, 2018 at 15:59 -
I'd buy you lunch, but all I can do is upvote.Chaim Eliyah– Chaim Eliyah2021年02月26日 21:53:00 +00:00Commented Feb 26, 2021 at 21:53
-
I appreciate the thought of the former, but will happily accept the latter (:DopeGhoti– DopeGhoti2021年03月01日 14:09:10 +00:00Commented Mar 1, 2021 at 14:09
-
What's the expected behavior when
set +e
is used? Is the expectation that the script ignores the error and continues to run, but trap ERR is nevertheless triggered?Sida Zhou– Sida Zhou2022年03月26日 02:22:44 +00:00Commented Mar 26, 2022 at 2:22
I find that I often want to avoid ERR trap but I don't want to discard the return code of my function either. So the pattern I use is this:
RC=0
some_function || RC=$?
Then I do whatever I need to do with RC.
-
1Brilliant! This can also be applied to subshells, e.g.
OUTPUT="$(some_function)" || RC="$?"
. Note that the assignment should be done outside the subshell, as its variables cannot be read from outside.Steen Schütt– Steen Schütt2024年01月15日 17:59:15 +00:00Commented Jan 15, 2024 at 17:59
You can enable/disable the ERR
trap during portions of you code as necessary.
#!/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
The ERR
trap obeys the same rules as set -e
, that is, it doesn't take effect on commands that are used as conditions. So,
trap "echo error" ERR
false # this should trigger the trap
if ! false; then # this shouldn't
echo handle stuff
fi
Remember that the command in the if
condition can be any command, it doesn't have to be [ .. ]
. So, if you only want a true/false evaluation of the exit status of a command, just use it directly in the if
condition.
If you need to save the exit code and avoid the ERR
trap, you'll need to do something like
somecmd && :; ret=$?
Here, the &&
will squash the ERR
trap, but since it only runs if the exit code is zero, we'll know the exit code is the same after :
.
You may want to check BashFAQ 105: Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?