5

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

6

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.

6
  • 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
    May 31, 2018 at 22:48
  • 2
    Just as with one command: if ! foo | bar | baz | quux; then stuff; fi.
    – DopeGhoti
    Jun 1, 2018 at 15:59
  • I'd buy you lunch, but all I can do is upvote. Feb 26, 2021 at 21:53
  • I appreciate the thought of the former, but will happily accept the latter (:
    – DopeGhoti
    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
    Mar 26, 2022 at 2:22
3

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
2

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?

2

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .