我刚刚发现,set -e
因为我正在寻找“如何运行许多命令(不带&&
)并立即停止其中任何命令的非零退出代码?”的答案。这set -e
对我来说已经足够好了,直到我发现
(set -e; false; echo here) || echo error
确实产生here
而不是error
.但当我很快找到一个新问题的解决方案时:
(set -e; false; echo here); [ $? -ne 0 ] && echo error
我还遇到了一个老问题,$?
而不是if cmd
(SC2181)。
现在我有一个新问题:我是否只是忽略 SC2181 错误,或者是否有适当的方法使其工作?
我也想过,trap
但不知道是否set -e
会产生任何信号。
注意
if ! (set -e; false; echo here); then
echo error
fi
也打印here
而不是error
.从外壳检查网站:
除了冗余之外,还有其他原因需要避免这种模式:
- [...]
set -e
如果命令失败,使用aka运行或调用的脚本errexit
将立即退出,即使它们后面跟着一个处理失败的子句。
这意味着该if
语句不受它的影响errexit
或禁用它。
另请注意,缺少()
或替换为{}
将停止执行下一个命令,包括错误检查命令。
PS 我想尝试尽可能减少脚本中的 ShellCheck 错误(这几乎总是表明脚本未优化或存在错误)。此外,使用附加运算符执行大量命令&&
恕我直言会降低代码的可读性和可编辑性,因此我想找到一个更干净的解决方案(至少对于 中的特定命令块()
)。
答案1
你总是可以作弊并做类似的事情:
last_block_failed() { return "$(( ! $? ))"; }
(set -o errexit
...
)
if last_block_failed; then
echo>&2 error
fi
或者类似的变体:
last_block_failed() (( ! $? ))
last_block_failed() { [ "$?" -ne 0 ]; }
last_block_failed() [[ $? -ne 0 ]]
请注意,在 bash 中(与 Bourne shell 和大多数其他允许任何命令的类 Bourne shell 相反),函数体必须是化合物命令,所以不起作用。命令组 ( last_block_failed() [ "$?" -ne 0 ]
{ ...; }
)((...))
和[[ ... ]]
都是复合命令。