将 set -e (errexit) 与命令块一起使用,并在该块失败时执行另一个命令 (SC2181)

将 set -e (errexit) 与命令块一起使用,并在该块失败时执行另一个命令 (SC2181)

我刚刚发现,set -e因为我正在寻找“如何运行许多命令(不带&&)并立即停止其中任何命令的非零退出代码?”的答案。这set -e对我来说已经足够好了,直到我发现

(set -e; false; echo here) || echo error

确实产生here而不是error.但当我很快找到一个新问题的解决方案时:

(set -e; false; echo here); [ $? -ne 0 ] && echo error

我还遇到了一个老问题,$?而不是if cmdSC2181)。

现在我有一个新问题:我是否只是忽略 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 ]不起作用。命令组 ( { ...; })((...))[[ ... ]]都是复合命令

相关内容