Bash

管道“假”不會給出非零結果程式碼

  • April 22, 2020

我理解這些:

true;   echo "$?"      # 0
false;  echo "$?"      # 1
true  | echo "$?"      # 0

但不是這個:

false | echo "$?"      # 0

…為什麼不列印1

我怎麼能在管道中強制失敗,然後得到1呢?

兩者的結果具有true | echo "$?"誤導false | echo "$?"性。的內容"$?"將在將命令傳遞給命令之前設置。false``echo

為了執行這些行,bash 設置了一個命令管道。管道已設置,然後命令並行啟動。所以在你的例子中:

true;   echo "$?"      # 0
false;  echo "$?"      # 1
true  | echo "$?"      # 0

是相同的:

true   
echo "$?"      # 0
false  
echo "$?"      # 1
echo "$?"      # 0

true在同時執行之前不執行echo $?

in false | echo $?,$?不是 的退出狀態false因為**$?展開為最近管道的十進制退出狀態

$$ 1 $$,而不是最近的命令子shell子程序。In false | echo $?,false不是管道,而只是其中的一部分。一個簡單的完整命令就像false;一個管道,即使不包含任何|. 假設它set -o pipefail是 on 並且退出狀態false | echo $?將是 of false$?也不能退出目前管道的狀態,因為目前管道在它回顯時尚未退出。

管道兩側(始終並行執行)的啟動或終止順序無關緊要,或者echo $?實際上是否在子程序或子shell中執行。

FWIW,當在子shell中時,變數和其他參數總是在目前子shell的上下文中擴展:iffalse | echo $?是通過為管道的兩側分叉單獨的程序來實現的(在bash中是這種情況,但不是在所有shell中),$?將在子程序中展開,在之後fork()並且可能在管道的左側退出之後

$$ 2 $$.

我怎麼能在管道中強制失敗,然後得到 1 呢?

您使用set -o pipefail,它在 bash、zsh 和 ksh 中受支持,應該包含在標準的未來版本中。但如上所述,這只影響管道退出$? 的值,而不影響管道本身。


$$ 1 $$ 2.5.2 SUSv4 標準中的特殊參數。在這種情況下,命令替換是否被視為管道取決於 shell;在大多數歷史和現在的 shell中:; echo exit 13 $?都會13列印0. $$ 2 $$一個可能有助於理解的簡單 bash 範例是echo $BASHPID >&2 | echo $BASHPID >&2 | echo $BASHPID >&2;在設置和執行 3 個子程序之前,不會擴展該BASHPID變數。像這樣的特殊參數在這方面並不特殊;它們像任何其他變數一樣被擴展。$?

引用自:https://unix.stackexchange.com/questions/581545