2015-12-17 20 views
12

使用bash進程替換,我想同時在一個文件上運行兩個不同的命令。在這個例子中,沒有必要設想一下,「cat/usr/share/dict/words」是一個非常昂貴的操作,例如解壓50GB的文件。bash過程替換和尾部不正確的結果?

cat /usr/share/dict/words | tee >(head -1 > h.txt) >(tail -1 > t.txt) > /dev/null 

該命令後我希望h.txt遏制的話,文件的第一行「A」,並t.txt包含文件「Zyzzogeton」的最後一行。

然而實際情況是,h.txt包含「A」,但t.txt包含大約5%的「argillaceo」到文件中。

爲什麼會發生這種情況?似乎無論是「尾巴」過程是提早結束還是混合起來。

運行一次像這樣的類似命令的行爲與預期:

cat /usr/share/dict/words | tee >(grep ^a > a.txt) >(grep ^z > z.txt) > /dev/null 

這個命令我期望a.txt中包含所有以「A」開頭的單詞後,在z.txt包含了所有的以「z」開頭的單詞,這正是發生的事情。

那麼,爲什麼這不與「尾巴」,以及與其他命令不起作用?

+1

我認爲這是關係到http://stackoverflow.com/questions/4489139/bash-process-substitution-and-syncing它表明,只要外層命令結束,替換退出的進程就會退出,但坦白地說,我無法證明這是目前任何命令的問題。到目前爲止已經嘗試過 –

回答

10

好吧,什麼似乎發生的是,一旦head -1命令完成退出並導致tee得到它試圖寫入該進程替換設置產生的EPIPE並根據man 2 write還將命名管道SIGPIPE在寫入過程中生成SIGPIPE,這導致tee退出並迫使tail -1立即退出,而左側的cat也得到SIGPIPE

我們可以看到這一點更好,如果我們添加更多一點的過程與head,使輸出都更具可預測性,並寫入stderr不依賴tee

for i in {1..30}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done") >(tail -1 > t.txt) >/dev/null 

,當我運行它給我的輸出:

1 
Head done 
2 

所以一切都退出之前,僅獲得1次循環的多次迭代(雖然t.txt仍然只有1 在裏面)。如果我們然後做

echo "${PIPESTATUS[@]}" 

我們看到

141 141 

this question關係到SIGPIPE在一個非常類似的方式,我們現在看到的是什麼。

coreutils維護者已將此作爲示例添加到未來後代的tee "gotchas"中。

對於有關如何融入POSIX標準,你可以在http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22195

看到(封閉notabug)報告,如果您有機會獲得GNU版本8的開發者的討論。24他們添加了一些選項(不在POSIX中),可以幫助像-p--output-error=warn。如果沒有,你可以採取一些風險,但通過捕獲和忽略SIGPIPE獲得問題所需的功能:

trap '' PIPE 
for i in {1..30}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done") >(tail -1 > t.txt) >/dev/null 
trap - PIPE 

將在兩個h.txtt.txt預期的結果,但是如果別的東西發生了通緝SIGPIPE要正確處理,你會不幸運用這種方法。

另一個哈克選擇是開始,然後不讓head進程列表中結束,直到它是非零長度之前歸零t.txt

> t.txt; for i in {1..10}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done"; while [ ! -s t.txt ]; do sleep 1; done) >(tail -1 > t.txt; date) >/dev/null 
+1

POSIX爲「tee」指定的行爲即使其中一個讀者退出也會繼續運行 - 所以如果您看到相反的東西,那實際上是一個錯誤。 –

+0

「如果寫入任何成功打開的文件操作數失敗,則寫入其他成功打開的文件操作數和標準輸出應繼續,但退出狀態應爲非零,否則將應用」實用程序描述默認值「中指定的默認操作。 - http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html –

+0

@CharlesDuffy以上結果適用於我認爲8.5的舊版本,我可以再試一次。另外,我還沒有深入研究過程替代是否表現爲關閉文件句柄,或者在過程結束時是否實際引發了SIGPIPE,在提交錯誤報告之前我還有更多工作要做。我猜 –