man bash includes this documentation for using trap:
trap [-lp] [[arg] sigspec ...]
…
The ERR trap is not executed if the failed command is part of the command list
immediately following a while or until keyword, part of the test in an if statement,
part of a && or || list, or if the command's return value is being inverted via !.
These are the same conditions obeyed by the errexit option.
…
I understand that “part of a && or || list” means that if a command is part of a list with these control operators, even if it has a non-zero exit status, it should not send an ERR signal (or exit the script if using set -o errexit).
And yet, here is a test script which seems to contradict this:
#!/usr/bin/env bash
_trap_err() {
local status=$? sig=$1 line=$2;
echo "Exit status ${status} on line ${line}: \`${BASH_COMMAND}\`";
}
trap '_trap_err ERR $LINENO' ERR;
function control_operators() {
# The next line will send an ERR signal.
[[ 1 -eq 2 ]] && echo Hello;
}
control_operators;
# The next line will not send an ERR signal.
[[ 1 -eq 2 ]] && echo Hello;
echo Done;
The output is:
❯ test.sh
Exit status 1 on line 14: `[[ 1 -eq 2 ]]`
Done
Because [[ 1 -eq 2 ]] is “part of a && or || list” it should not trigger an ERR signal.
The expected output is:
❯ test.sh
Done
Furthermore, only the list [[ 1 -eq 2 ]] && echo Hello inside the control_operators function sends the ERR signal, but the [[ 1 -eq 2 ]] && echo Hello outside the function does not.
The options set in the environment of this script are (output from set -o | grep 'on$'):
braceexpand on
hashall on
interactive-comments on
xtrace on
Questions:
- Is this behavior normal, or am I using control operators in a list incorrectly (or interpreting the documentation incorrectly)?
- What is the best way to avoid triggering an ERR trap when commands are part of a conditional expression and do not actually constitute an errored state?
- One option is to add
|| trueto the end of every list with control operators. - Another option is to use
if [[ 1 -eq 2 ]]; then echo Hello; fiinstead of the&&shorthand; this does not cause an ERR signal to be sent, because (according toman bash) “part of the test in an if statement” – although I’m confused why this works when “part of a && or || list” doesn’t.
- One option is to add
- Why does
[[ 1 -eq 2 ]]send an ERR signal only when inside a function?