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.
$1 means an input argument and -z means non-defined or empty. You're testing whether an input argument to the script was defined when running the script.
In Bash, the set command allows you to manage certain flags and characteristics to influence how your bash scripts behave. These controls ensure that your scripts follow the correct path and that Bash's peculiar behavior does not cause difficulties.
Set –e is used within the Bash to stop execution instantly as a query exits while having a non-zero status. This function is also used when you need to know the error location in the running code.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With