有人可以在下面的代码片段中解释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)
与注释相关的其他注释(无论如何都要感谢所有建议):
答案 0 :(得分:3)
让我们简化一下;所需的最小代码量 重现您正在处理的问题
set -e
: $((+)) # arithmetic expansion error
echo survived
根据标准,此内容永远不要打印survived
,it says a POSIX shell running non-interactively shall immediately exit upon an expansion error。但是貌似Bash并不这么认为。尽管此差异未在手册页中明确记录,但在description of POSIX mode中指出
- 如果算术中的语法错误,则非交互式shell退出 扩展会导致表达式无效。
我们可以说这意味着在其默认操作模式下,非交互式Bash会话不会在发生此类错误时退出,但是正如您所意识到的那样,它也不触发errexit机制或ERR陷阱。相反,它会为$?
继续前进分配一个非零值。
要克服此问题并获得预期的行为,您应按以下方式定义reproduce
function reproduce() (
# Trigger arithmetic error on purpose
a=$((1109962735 - hello=12272 + 1))
)
这样,扩展错误将在子外壳中发生,并使其以非零状态退出,因此errexit和trap将能够捕获该错误。
根据破折号-o的请求,此版本可在表达式有效时为当前执行环境设置a
function reproduce() {
if : $((expression)); then
a=$((expression))
fi
}
答案 1 :(得分:2)
从表面上看,bash似乎不会因各种SYNTAX错误而触发陷阱。仅当执行命令(外部,内置)(并返回非零)时,才会触发ERR陷阱。
在手册页中:
如果sigspec为ERR,则每当管道执行命令arg (可能由一个简单的命令组成),列表或复合 命令返回一个非零的退出状态,但必须遵守以下条件 条件...
ERR陷阱仅适用于 PIPELINE 。如果bash识别出语法错误,它将在执行管道之前中止,因此没有陷阱。即使他的'-e'文档指定了相同的条件(if a pipeline ... exit with non-zero status
),但观察到的行为还是不同的。
如果您尝试其他扩展-例如命令扩展-陷阱被触发,因为有管道执行:
如果在算术扩展中使用try各种语法错误,则不会触发陷阱-没有管道。
此外,其他bash语法错误也不会触发陷阱:()
,[[ ]]
。
我找不到不需要对源脚本进行大量更改的解决方案。可能会向bash团队提出错误/功能请求?