This is from the manual for bash set options (for set -E
)
-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 does "trap on ERR" mean? what does "trap on ERR is inherited by shell functions in a subshell environment"? Can a shell script proceed even after the trap and the trap is passed to a subshell? Can someone elaborate on this with a simple example, please?
The Bash manual on trap
says:
trap [-lp] [arg] [sigspec …]
…
If a sigspec is
ERR
, the command arg is executed whenever a pipeline (which may consist of a single simple command), a list, or a compound command returns a non-zero exit status, subject to the following conditions. TheERR
trap is not executed if the failed command is part of the command list immediately following anuntil
orwhile
keyword, part of the test following theif
orelif
reserved words, part of a command executed in a&&
or||
list except the command following the final&&
or||
, any command in a pipeline but the last, or if the command’s return status is being inverted using!
. These are the same conditions obeyed by theerrexit
(-e
) option.
The material you quote says that trap '…' ERR
is not normally inherited by a shell function, a command substitution or commands executed in a subshell environment. However, if you use set -E
, then the ERR
trap is inherited.
The sentence means:
set -E
is set, then any trap on ERR is inherited by shell functions.set -E
is set, then any trap on ERR is inherited by command substitutions.set -E
is set, then any trap on ERR is inherited by commands executed in a subshell environment.The 'in a subshell environment' clause does not apply to shell functions or command substitutions.
I can't parse your question "Can a shell script proceed even after the trap and the trap is passed to a subshell?" A shell script can proceed after a trap — what happens depends on the commands in the arg
part of the trap
command.
Here's a shell script that demonstrates set -E
in action:
#!/bin/bash
#
# SO 6485-2814 'trap ERR and set -E'
trap 'echo TRAP ERR >&2' ERR
echo begin-ls
ls /non-existent
echo end-ls
func()
{
echo begin-func
ls /non-existent
echo end-func
}
echo invoke-func
func
echo finish-func
echo begin-substitution
echo $(date): $(ls /non-existent)
echo end-substitution
echo begin-subshell
(ls /non-existent)
echo end-subshell
set -E
echo invoke-func
func
echo finish-func
echo begin-substitution
echo $(date): $(ls /non-existent)
echo end-substitution
echo begin-subshell
(ls /non-existent)
echo end-subshell
When run, it produces:
begin-ls
ls: /non-existent: No such file or directory
TRAP ERR
end-ls
invoke-func
begin-func
ls: /non-existent: No such file or directory
end-func
finish-func
begin-substitution
ls: /non-existent: No such file or directory
Sun Nov 15 23:16:25 MST 2020:
end-substitution
begin-subshell
ls: /non-existent: No such file or directory
end-subshell
invoke-func
begin-func
ls: /non-existent: No such file or directory
TRAP ERR
end-func
finish-func
begin-substitution
ls: /non-existent: No such file or directory
Sun Nov 15 23:16:25 MST 2020:
end-substitution
begin-subshell
ls: /non-existent: No such file or directory
end-subshell
As you can see, the ERR
trap fires on the failing ls
command run on its own, but doesn't fail when run in a function or in a subshell or as part of (some) command substitutions.
When the set -E
option is set, the ERR
trap fires when the command failed in the function, in the subshell, and in the command substitution.
Curiously, the ERR
trap does fire in a command substitution like x=$(ls /non-existent)
but not in the more complex example shown above. I'm not clear whether that's supposed to happen.
I'm using GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
— it's possible that later versions of Bash (4.x) do not behave the same.