管道“假”不會給出非零結果程式碼
我理解這些:
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 $?
將是 offalse
,$?
也不能退出目前管道的狀態,因為目前管道在它回顯時尚未退出。管道兩側(始終並行執行)的啟動或終止順序無關緊要,或者
echo $?
實際上是否在子程序或子shell中執行。FWIW,當在子shell中時,變數和其他參數總是在目前子shell的上下文中擴展:if
false | 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
變數。像這樣的特殊參數在這方面並不特殊;它們像任何其他變數一樣被擴展。$?