Bash set -e 不立即退出并出现 pipefail

Bash set -e not exiting immediately with pipefail

set -eo pipefail

commandThatFails || exitFunction

exitFunction

所以这个脚本是 运行 exitMethod 两次...我认为 set -e 在任何非零退出代码上立即退出并且 set -o pipefail 确保在管道期间任何失败都是最终退出状态代码不是最近的命令?

所以我想:

  1. commandThatFails
  2. 执行 exitFunction
  3. set -o pipefail returns 非零退出代码作为第一个命令失败
  4. set -e 检测到非零退出代码并立即退出

在文档中指出:

The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.

我以为exitfunction是command following the final ||所以会被计算并立即退出。

我可以通过以下方式解决问题:

commandThatFails || { exitFunction; exit 1; }

但这似乎不是处理此问题的更优雅的方式,任何想法都值得赞赏!

||是流量控制算子,不是管道组件。 pipefail对它没有影响。

如果 set -e 导致流量控制操作符退出,那么您的脚本 运行 的 else 分支永远不会处于活动状态;这将完全没有用。

因此,&&|| 抑制其左侧的 set -e 行为,就像 if condition; then success; else fail; fi 抑制 condition 的行为一样.


一般做法是让你的exitFunction实际调用exit,所以你可以这样写:

die() {
  rc=$?
  (( $# )) && printf '%s\n' "$*" >&2
  exit "$(( rc == 0 ? 1 : rc ))"
}

commandThatFails || die "commandThatFails failed"

...但是如果你想先调用其他东西,是的,你需要使用分组,就像你在问题中所做的那样。