According to man bash
,
set -e
Exit immediately if (snip). A trap on
ERR
, if set, is executed before the shell exits.
However, the script below doesn't invoke the ERR
trap.
trap 'echo ERR; sleep 1' ERR
trap 'echo EXIT; sleep 1' EXIT
set -e
array=(a b c)
echo $(( ${#array[@] - 1)) #note the closing bracket } is forgotten
echo "after"
The expected result is
$ bash script.sh
4.sh: line 7: ${#array[@] - 1: bad substitution
ERR
EXIT
# and then shell exits
The actual result is
$ bash script.sh
4.sh: line 7: ${#array[@] - 1: bad substitution
EXIT
# and then shell exits
If I delete the line set -e
, then
$ bash script2.sh
4.sh: line 7: ${#array[@] - 1: bad substitution
after #the last echo command is executed
EXIT
This means set -e
catches the syntax error. Why isn't the ERR
trap invoked although the shell does exit?
Environment:
I tested the script on two machines.
$ bash --version
GNU bash, version 4.4.12(1)-release (arm-unknown-linux-gnueabihf)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ bash --version
GNU bash, version 5.0.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Supplement:
According to the posted answers, it is natural the trap isn't executed and this is because echo $(( ${#array[@] - 1))
doesn't complete its execution to return exit status. Is my understanding right?
However, man bash
explains set -e
as
Exit immediately if a pipeline (which may consist of a single simple command), a list, or a compound command (see SHELL GRAMMAR above), exits with a non-zero status.
I think this also requires the command to complete. If echo $(( ${#array[@] - 1))
doesn't complete its execution, I believe set -e
should not work here and echo "after"
should be executed.
Supplement2:
According to oguz ismail's comment, this is a documentation issue. POSIX says set -e
shall exit the shell when
non-zero exit status is returned (as you can see in
man bash
)or shell error occurs
and shell error includes syntax error. But man bash
is missing the explanation for the second case, right? If so, everything is consistent other than the fact that man bash
doesn't explain the implementation accurately and the statement "These are the same conditions obeyed by the errexit
(-e
) option." found in the trap
's explanation in man bash
.