2014-02-12 30 views
5

我遇到了BASH無限循環的某些奇怪行爲,其輸出被流水線化到另一個進程。也就是說,我運行這兩個命令:從BASH退出管道中的無限循環

(while true; do echo xxx; done) | head -n 1 
(while true; do date; done) | head -n 1 

第一個退出瞬間,而第二個沒有(我相信它會永遠運行下去,而不被殺害)。我也嘗試了一個隱含的無限循環:

yes | head -n 1 

它也會自行退出。每種情況下都會立即在屏幕上打印出適當的輸出行。我只是好奇什麼決定了這樣一個委員會是否會完成。

+1

注意,括號是不必要的; 「while」循環本身就是一個完整的命令,可以是管道的左側。 – chepner

回答

7

head退出時,括號化表達式的標準輸出關閉。如果使用外部命令(如date),則該循環掛起。如果使用bash的內部命令,如echo,則循環退出。爲證明,請使用

(while true; do /bin/echo xxx; done) | head -n 1 

它會掛起。如果您使用

(while true; do date; echo $? 1>&2; sleep 1; done) | head -n 1 

你會看到,在第二輪比賽中,date命令返回一個錯誤退出代碼,即其他,但沒有任何東西。 Bash顯然不像內部命令出現問題那麼嚴重。我不知道這是否是有意的,或者是一個在bash中的錯誤。

要確保退出循環,這似乎工作:

(set -e; while true; do date ; done) | head -n 1 
+0

謝謝,這很有道理。 –

+3

退出的唯一過程是當'head'退出時,試圖寫入留下的關閉文件句柄的過程。當外部程序'date'是「受害者」時,'bash' shell將繼續,不斷產生試圖寫入和接收'SIGPIPE'的'date'進程。有了內建,它就是'bash'外殼本身接收到'SIGPIPE',所以它退出,終止管道。 – chepner

+0

'set -e'的工作原理是,當'date'第一次嘗試寫入關閉的文件句柄時,它會以非零狀態退出,這會導致運行while循環的'bash' shell也會按照用'-e'選項。 – chepner