[英]Bash exit status not caught despite set -e and/or trap being active
有人可以解释下面代码片段中的 bash/set -e 行为吗?
#!/bin/bash
# Comment if you want to test the trap only
set -e -o pipefail -u -E
# Comment if you want to test the set -e only
trap "echo ERROR CAUGHT; exit 12" ERR
function reproduce() {
# Trigger arithmetic error on purpose
a=$((1109962735 - hello=12272 + 1))
}
reproduce
# The script is expected to trigger the trap and/or activate the set -e. In both cases it should stop and exit here on error.
status_code=$?
echo "STATUS ${status_code}"
if [[ "${status_code}" != "0" ]];then
echo "FIXME: why was status code not caught by set -e ?"
echo "Executing false to prove set -e is still active"
false
# If the following is not executed then it proves -e is still active
echo "set -e not active !!!!!"
exit 2
fi
这是执行它时获得的内容:
$ bash reproduce.sh
reproduce.sh: line 8: 1109962735 - hello=12272 + 1: attempted assignment to non-variable (error token is "=12272 + 1")
STATUS 1
FIXME: why was status code it not caught by set -e ?
Executing false to prove set -e is still active
ERROR CAUGHT
检查退出代码
$ echo $?
1
Bash版
bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
转载以及
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
与评论相关的附加说明(无论如何感谢所有建议):
让我们简化它; 重现您正在处理的问题所需的最少代码量是
set -e
: $((+)) # arithmetic expansion error
echo survived
根据标准,这不应该打印survived
, 它说非交互运行的 POSIX shell 应在扩展错误时立即退出。 但貌似Bash不这么认为。 尽管手册页中没有明确记录这种差异,但在POSIX 模式的描述中它说
- 如果算术扩展中的语法错误导致表达式无效,则非交互式 shell 退出。
我们可以说这意味着在其默认操作模式下,非交互式 Bash session 不会在出现此类错误时退出,但正如您所意识到的,它也不会触发 errexit 机制或 ERR 陷阱。 相反,它为$?
继续前进。
为了克服这个问题并获得预期的行为,您应该如下定义reproduce
function reproduce() (
# Trigger arithmetic error on purpose
a=$((1109962735 - hello=12272 + 1))
)
这样,扩展错误将发生在子shell中,并导致它以非零状态退出,因此,errexit 和 trap 将能够捕获它。
根据 dash-o 的要求,这里有一个版本,它在表达式有效时为当前执行环境设置a
function reproduce() {
if : $((expression)); then
a=$((expression))
fi
}
从表面上看,bash 似乎不会触发各种 SYNTAX 错误的陷阱。 仅当执行命令(外部、内置)(并返回非零)时,才会触发 ERR 陷阱。
从手册页:
如果 sigspec 是 ERR,则只要管道(可能由单个简单命令组成)、列表或复合命令返回非零退出状态,就会执行命令 arg,但需满足以下条件...
ERR 陷阱仅适用于PIPELINE 。 如果 bash 识别出语法错误,它会在执行管道之前中止,因此没有陷阱。 即使他的“-e”文档指定了相同的条件( if a pipeline... exit with non-zero status
),观察到的行为是不同的。
如果您尝试其他扩展 - 例如命令扩展 - 将触发陷阱,因为存在管道执行:
如果在算术扩展中使用尝试各种语法错误,则陷阱未触发 - 没有管道。
此外,其他 bash 语法错误不会触发陷阱: ()
, [[ ]]
。
我找不到不需要对源脚本进行大量更改的解决方案。 可以向 bash 团队提交错误/功能请求吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.