lon*_*nix 7 bash pipe exit-status
我明白这些:
true; echo "$?" # 0
false; echo "$?" # 1
true | echo "$?" # 0
Run Code Online (Sandbox Code Playgroud)
但不是这个:
false | echo "$?" # 0
Run Code Online (Sandbox Code Playgroud)
...为什么不打印1?
我怎么能在管道中强制失败,然后再得到1呢?
Phi*_*ing 15
两者的结果true | echo "$?"和false | echo "$?"误导。的内容"$?"将在将命令通过管道false传输到命令之前设置echo。
为了执行这些行,bash 设置了一个命令管道。管道已设置,然后命令并行启动。所以在你的例子中:
true; echo "$?" # 0
false; echo "$?" # 1
true | echo "$?" # 0
Run Code Online (Sandbox Code Playgroud)
是相同的:
true
echo "$?" # 0
false
echo "$?" # 1
echo "$?" # 0
Run Code Online (Sandbox Code Playgroud)
true在同时执行之前不执行echo $?。
在false | echo $?,$?不是false因为$?扩展到最近管道[1]的十进制退出状态,而不是最近的命令、子shell或子进程的退出状态。在false | echo $?,false不是管道,而只是管道的一部分。一个简单的完整命令就像false;一个管道,即使不包含任何|.
假设set -o pipefail是 on 并且 的退出状态false | echo $?将是false,$?也不能退出当前管道的状态,因为当前管道在它回应它时还没有退出。
管道两侧(始终并行运行)的启动或终止顺序无关,或者echo $?实际上是在子进程还是子shell 中运行都无关紧要。
FWIW,当在子shell中时,变量和其他参数总是在当前子shell的上下文中扩展:如果false | echo $?是通过为管道的两侧分叉单独的进程来实现的(在bash中是这种情况,但不是在所有shell中),$?将在子进程被扩展,之后的fork()管道的左侧已退出[2],和之后可能。
我怎么能在管道中强制失败,然后得到 1?
您使用set -o pipefail,它在 bash、zsh 和 ksh 中受支持,并且应该包含在标准的未来版本中。但如上所述,这只影响管道退出$? 后的值,而不影响管道本身。
[1] 2.5.2 SUSv4 标准中的特殊参数。在这种情况下,命令替换是否被视为管道取决于 shell;在大多数历史和现在的 shell 中:; echo `exit 13` $?都会打印13,但在某些(如 dash、yash 或 pdksh 派生的)中它会打印0.
[2] 一个可能有助于理解的简单 bash 示例是echo $BASHPID >&2 | echo $BASHPID >&2 | echo $BASHPID >&2;在设置和运行 3 个子进程之前,不会扩展该BASHPID变量。特殊参数 like在这方面并不特殊;它们像任何其他变量一样被扩展。$?