我們可以在 tee(或 pee)命令中使用 $PIPESTATUS 嗎?
在我的 bash 腳本中,我經常使用管道,並且想知道管道的哪個階段導致出現錯誤時出現問題。這些片段的基本結構是:
#!/bin/bash ProduceCommand 2>/dev/null | ConsumeCommand >/dev/null 2>&1 PipeErrors=("${PIPESTATUS[@]}") [[ "${PipeErrors[0]}" -eq '0' ]] || { HandleErrorInProduceCommand; } [[ "${PipeErrors[1]}" -eq '0' ]] || { HandleErrorInConsumeCommand; }
tee
現在(第一次很有趣)我處於這樣一種情況,如果我可以使用or ,那就太好了pee
。但是$PIPESTATUS
在使用這些命令時會發生什麼?例如:#!/bin/bash ProduceCommand 2>/dev/null | tee >(ConsumeCommand1) >(ConsumeCommand2) >/dev/null 2>&1 PipeErrors=("${PIPESTATUS[@]}")
或者
#!/bin/bash ProduceCommand 2>/dev/null | pee ConsumeCommand1 ConsumeCommand2 2>/dev/null PipeErrors=("${PIPESTATUS[@]}")
我相信在這兩種情況下都
${PipeErrors[0]}
反映了ProduceCommand
. 此外,假設它分別${PipeErrors[1]}
反映了tee
或pee
本身的錯誤狀態是合乎邏輯的。但這導致我至少遇到兩個理解問題:
tee
or的錯誤狀態(返回值)是pee
什麼?我在手冊頁中沒有找到關於這一點的準確陳述。如果其中一個消費命令失敗,它們是否會返回硬編碼的錯誤狀態,或者它們是否會以某種方式傳遞消費命令的錯誤狀態(ssh
例如)?如果是前者,我們如何找出哪些消耗命令是罪魁禍首?如果是後者,中繼哪個錯誤狀態?僅僅是首先失敗的命令嗎?- AFAIK、bash 或
tee
orpee
命令本身分別在內部使用管道(fifos)來獲取ProduceCommand
消耗命令的輸出。這意味著我們有一個管道,其(第一個,在這種情況下,唯一的)接收端是一個管道本身。這不應該影響$PipeErrors
上面的範常式式碼,但我真的不確定。有人可以對此有所了解嗎?
什麼是錯誤狀態(返回值)
tee
能夠將所有數據複製到所有輸出文件時為 0,否則為 >0。請參閱規範。GNU coreutils 的實現有額外
tee
的選項可以在寫入管道時忽略錯誤(如那些用於實現的>(...)
):$ seq 1024 | tee >(false) >/dev/null; echo $? 141 $ seq 1024 | tee -p >(false) >/dev/null; echo $? 0
沒有選項可以知道哪些輸出失敗(如果有)
$$ 1 $$.
但是您的問題似乎是關於在
>(..)
程序替換中執行的命令的退出狀態是否以任何方式反映在 中PIPESTATUS
,或者是否可以以任何方式反映在PIPESTATUS
.答案是否定的。
首先,請注意它
>(...)
更像是... &
後台命令而不是...|...
管道命令。在如下片段中:... | tee >(cmd ...) | ...; echo ${PIPESTATUS[@]}
無法保證
cmd
在您執行時已經完成echo ${PIPESTATUS[@]}
。但它們並不完全一樣
...&
,因為你不能wait
為它們獲取它們的狀態,也不能從中獲取它們的狀態$!
——除非在一些有限的情況下,它們不包括它們與tee
或其他外部命令的使用:$ bash -c 'echo 1 | tee >(sleep 2; sed s/1/2/); wait; echo DONE' 1 DONE $ <after two seconds> 2
如您所見,
tee
主 shell 都在>(...)
.$$ 1 $$執行輸出“子命令
pee
”本身(並等待它們完成)的命令可能更智能,並在其退出狀態中反映其中哪些失敗(例如,通過將第 1 位設置為第一個,將第 2 位設置為第二個,等等,最多 8 個子命令),但也不做這樣的事情。