I have a simple script :
#!/bin/bash
set -e
trap "echo BOO!" ERR
function func(){
ls /root/
}
func
I would like to trap ERR if my script fails (as it will here b/c I do not have the permissions to look into /root). However, when using set -e
it is not trapped. Without set -e
ERR is trapped.
According to the bash man page, for set -e
:
... A trap on ERR, if set, is executed before the shell exits. ...
Why isn't my trap executed? From the man page it seems like it should.
chepner's answer is the best solution: If you want to combine set -e
(same as: set -o errexit
) with an ERR
trap, also use set -o errtrace
(same as: set -E
).
In short: use set -eE
in lieu of just set -e
:
#!/bin/bash
set -eE # same as: `set -o errexit -o errtrace`
trap 'echo BOO!' ERR
function func(){
ls /root/
}
# Thanks to -E / -o errtrace, this still triggers the trap,
# even though the failure occurs *inside the function*.
func
A more sophisticated example trap
example that prints the message in red and also prints the exit code:
trap 'printf "\e[31m%s: %s\e[m\n" "BOO!" $?' ERR
man bash
says about set -o errtrace
/ set -E
:
If set, any trap on ERR is inherited by shell functions, command substitutions, and commands executed in a subshell environment. The ERR trap is normally not inherited in such cases.
What I believe is happening:
Without -e
: The ls
command fails inside your function, and, due to being the last command in the function, the function reports ls
's nonzero exit code to the caller, your top-level script scope. In that scope, the ERR
trap is in effect, and it is invoked (but note that execution will continue, unless you explicitly call exit
from the trap).
With -e
(but without -E
): The ls
command fails inside your function, and because set -e
is in effect, Bash instantly exits, directly from the function scope - and since there is no ERR
trap in effect there (because it wasn't inherited from the parent scope), your trap is not called.
While the man
page is not incorrect, I agree that this behavior is not exactly obvious - you have to infer it.