trap 上的 Bash 手册说:
trap [-lp] [arg] [sigspec …]
…
如果 sigspec 是 ERR,则只要管道(可能包含单个简单命令)、列表或复合命令返回非零退出,就会执行命令 arg状态,受以下条件限制。如果失败的命令是紧跟在until 或while 关键字之后的命令列表的一部分,则不会执行ERR 陷阱,这是if 或elif 保留字之后的测试的一部分,是命令的一部分在&& 或|| 列表中执行,除了最后一个&& 或|| 之后的命令,管道中除最后一个之外的任何命令,或者如果命令的返回状态正在使用! 反转。这些与errexit (-e) 选项所遵循的条件相同。
您引用的材料说trap '…' ERR 通常不会被shell 函数、命令替换或在子shell 环境中执行的命令继承。但是,如果您使用set -E,则ERR 陷阱将被继承。
这句话的意思是:
- 如果设置了
set -E,则 ERR 上的任何陷阱都会被 shell 函数继承。
- 如果设置了
set -E,则 ERR 上的任何陷阱都会被命令替换继承。
- 如果设置了
set -E,则ERR 上的任何陷阱都会被在子shell 环境中执行的命令继承。
'in a subshell environment' 子句不适用于 shell 函数或命令替换。
我无法解析您的问题“即使在陷阱和陷阱传递给子shell 之后,shell 脚本还能继续执行吗?” shell 脚本可以在陷阱之后继续执行 — 发生的情况取决于 trap 命令的 arg 部分中的命令。
这是一个演示 set -E 实际操作的 shell 脚本:
#!/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
运行时会产生:
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
如您所见,ERR 陷阱会在失败的 ls 命令自行运行时触发,但在函数或子 shell 中运行或作为(某些)命令替换的一部分时不会失败。
当设置了set -E 选项时,ERR 陷阱会在函数、子shell 和命令替换中的命令失败时触发。
奇怪的是,ERR 陷阱确实会在像x=$(ls /non-existent) 这样的命令替换中触发,但在上面显示的更复杂的示例中不会触发。我不清楚这是否应该发生。
我正在使用GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) — 更高版本的 Bash (4.x) 的行为可能不同。