0

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?

Chan Kim
  • 5,177
  • 12
  • 57
  • 112

2 Answers2

2

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. The ERR trap is not executed if the failed command is part of the command list immediately following an until or while keyword, part of the test following the if or elif 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 the errexit (-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:

  • If set -E is set, then any trap on ERR is inherited by shell functions.
  • If set -E is set, then any trap on ERR is inherited by command substitutions.
  • If 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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Ah, that explains it. In my case, there was a difference : sub-shell inherited the trap before setting -E. Anyway, now I can understand it. Thank you very much! – Chan Kim Nov 16 '20 at 08:18
0

A minor edit in the script shared by Jonathan Leffler. The edit is to contain the ls executed directly (without command substitution, function call, and subshell) with the -E option set. Also, attached is the output as from execution on bash 5.0.17(1)-release. In this output, it can be seen that the TRAP fires for all four cases, namely, execution of command directly from the script, in a function, in a subshell, and in a command substitution. Whereas in the output shared by Jonathan Leffler, the TRAP does not seem to be fired for command substitution and subshell even with the -E flag set.

The script:

#! /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
echo ""

func()
{
    echo begin-func
    ls /non-existent
    echo end-func
}

echo invoke-func
func
echo finish-func
echo ""

echo begin-substitution
echo $(date): $(ls /non-existent)
echo end-substitution
echo ""

echo begin-subshell
(ls /non-existent)
echo end-subshell

echo "************ Set -E ****************"
set -E
echo begin-ls
ls /non-existent
echo end-ls
echo ""

echo invoke-func
func
echo finish-func
echo ""

echo begin-substitution
echo $(date): $(ls /non-existent)
echo end-substitution
echo ""

echo begin-subshell
(ls /non-existent)
echo end-subshell

Output: begin-ls ls: cannot access '/non-existent': No such file or directory TRAP ERR end-ls

invoke-func
begin-func
ls: cannot access '/non-existent': No such file or directory
end-func
finish-func

begin-substitution
ls: cannot access '/non-existent': No such file or directory
Monday 31 January 2022 01:45:06 PM IST:
end-substitution

begin-subshell
ls: cannot access '/non-existent': No such file or directory
TRAP ERR
end-subshell
************ Set -E ****************
begin-ls
ls: cannot access '/non-existent': No such file or directory
TRAP ERR
end-ls

invoke-func
begin-func
ls: cannot access '/non-existent': No such file or directory
TRAP ERR
end-func
finish-func

begin-substitution
ls: cannot access '/non-existent': No such file or directory
TRAP ERR
Monday 31 January 2022 01:45:06 PM IST:
end-substitution

begin-subshell
ls: cannot access '/non-existent': No such file or directory
TRAP ERR
end-subshell
Kulwant Singh
  • 121
  • 2
  • 12