PIPESTATUS 忽略否定?

PIPESTATUS ignores negation?

我刚刚在 bash(版本 4.2.25(1)-release)中发现了以下结果:

$ true; echo "${PIPESTATUS[@]}"
0
$ ! true; echo "${PIPESTATUS[@]}"
0
$ false; echo "${PIPESTATUS[@]}"
1
$ ! false; echo "${PIPESTATUS[@]}"
1
$ true && false; echo "${PIPESTATUS[@]}"
1
$ true && ! false; echo "${PIPESTATUS[@]}"
1

所以,$PIPESTATUS 似乎在所有情况下都忽略了否定。这是一个已知的问题?我找不到任何相关信息。或者这是通缉行为?如果是这样,背后的原因是什么?

使用子 shell 时,一切如我所料:

$ (true && ! false); echo "${PIPESTATUS[@]}"
0

我认为这种行为是有意,如果用完整的管道查看会变得更清楚:

a | b | c | d ; echo "${PIPESTATUS[@]}"

这将显示进程 abcd.

的退出状态

现在,否定仅适用于完整管道的退出状态:

! a | b | c | d ; echo "${PIPESTATUS[@]}"

不允许对部分管道取反:

a | ! b | c | d   # Syntax error at "| !"

因为这种方法,管道关联比否定更强(可以说这是关联级别的! (a | b | c | d)),所以管道成分的结果不受否定的影响,因为在评估管道后,稍后应用否定。

! a | b | c 被 shell 解释为 !{a | b | c;} 而不是 {! a;} | b | c

单个命令退出状态存储在 ${PIPESTATUS[@]}.

$?是指整个命令的退出状态,包括!

您可以通过实际生成子 shell 来强制 (! a) | b | c。例如

$ true; echo "${PIPESTATUS[@]}"
0
$ (! true); echo "${PIPESTATUS[@]}"
1
$ false; echo "${PIPESTATUS[@]}"
1
$ (! false); echo "${PIPESTATUS[@]}"
0