语法错误时不执行“ERR”陷阱

ynn*_*ynn 5 bash bash-trap

根据man bash

set -e

如果(剪断)立即退出。如果设置了上的陷阱ERR,则会在 shell 退出之前执行。

但是,下面的脚本不会调用ERR陷阱。

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"
Run Code Online (Sandbox Code Playgroud)

预期结果是

$ bash script.sh 
4.sh: line 7:  ${#array[@] - 1: bad substitution
ERR
EXIT
# and then shell exits
Run Code Online (Sandbox Code Playgroud)

实际结果是

$ bash script.sh 
4.sh: line 7:  ${#array[@] - 1: bad substitution
EXIT
# and then shell exits
Run Code Online (Sandbox Code Playgroud)

如果我删除该行set -e,那么

$ bash script2.sh
4.sh: line 7:  ${#array[@] - 1: bad substitution
after #the last echo command is executed
EXIT
Run Code Online (Sandbox Code Playgroud)

这意味着set -e捕获语法错误。ERR尽管 shell确实退出了,但为什么陷阱没有被调用?


环境:

我在两台机器上测试了该脚本。

$ 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.
Run Code Online (Sandbox Code Playgroud)
$ 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.
Run Code Online (Sandbox Code Playgroud)

补充:

根据发布的答案,陷阱不被执行是很自然的,这是因为echo $(( ${#array[@] - 1))没有完成其执行以返回退出状态。我的理解对吗?

然而,man bash解释set -e

如果管道(可能由单个简单命令组成)、列表或复合命令(请参阅上面的 SHELL GRAMMAR)以非零状态退出,请立即退出。

我想这也需要命令来完成。如果echo $(( ${#array[@] - 1))没有完成其执行,我相信set -e不应该在这里工作并且echo "after"应该被执行。


补充2:

根据oguz ismail 的评论,这是一个文档问题。POSIX表示set -e应退出 shell

  • 返回非零退出状态(如您在 中看到的man bash

  • 或者 发生shell错误

shell错误包括语法错误。但man bash缺少对第二种情况的解释,对吧?如果是这样,除了man bash没有准确解释实现以及“这些是errexit( -e) 选项遵循的相同条件”这一事实之外,一切都是一致的。trap中的解释中找到man bash

cda*_*rke 1

ERR陷阱从不捕获语法错误,也不是为此而设计的。从man bash

  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 ...
Run Code Online (Sandbox Code Playgroud)

在这种情况下,该命令永远不会执行,因此不会返回非零状态,脚本在此之前会失败。