如何导致 Linux 管道失败?

How to cause a Linux pipeline to fail?

最近我在 Ubuntu 14.04 学习 POSIX shell 的 set -e。我的参考 material 是 "IEEE Std 1003.1-2008, 2016 Edition"、"Shell & Utilities" 章节。从 this section 我看到 -e 不会导致脚本在管道中的命令失败时退出(除非失败的命令是管道中的最后一个):

The failure of any individual command in a multi-command pipeline shall not cause the shell to exit. Only the failure of the pipeline itself shall be considered.

然后我写了一个简单的脚本来确认这个行为:

(
    set -e
    false | true | false | true
    echo ">> Multi-command pipeline: Last command succeeded."
)
(
    set -e
    false | true | false
    echo ">> Multi-command pipeline: Last command failed."
)

"Last command succeeded" 消息被打印出来,而 "Last command failed" 消息没有。

我的问题是:

在 bash 中默认情况下,管道的成功或失败仅由管道中的最后一个命令决定。

但是您可以启用 pipefail 选项 (set -o pipefail),如果管道中的任何命令失败,管道将 return 失败。

例子

此管道成功:

$ false | true | false | true ; echo $?
0

此管道失败:

$ set -o pipefail
$ false | true | false | true ; echo $?
1

文档

来自man bash

The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.

The chained commands false | true | false don't seem to be a failure of the pipeline. It's just the failure of the last command. The pipeline itself still succeeds. Am I right?

管道的成功被指定为最后一个命令的成功。它们是同一回事。

来自§2.9.2 Pipelines

If the pipeline does not begin with the ! reserved word, the exit status shall be the exit status of the last command specified in the pipeline. Otherwise, the exit status shall be the logical NOT of the exit status of the last command. That is, if the last command returns zero, the exit status shall be 1; if the last command returns greater than zero, the exit status shall be zero.

在 bash 和 ksh 中,您可以使用 set -o pipefail 使管道在任何命令失败时失败。不幸的是,这是 not a POSIX option。应该是,但不是。