2014-04-15 74 views
5

我試圖用FIFO做一些簡單的事情:讀取行,但不是一次全部完成,而且它意外地「沒有工作」。在shell腳本中使用mkfifo

這是OK:

$ f=$(mktemp -u) 
$ mkfifo $f 
$ { seq 5 > $f; } & 
[1] 2486 
$ while read line; do echo $line; done < $f 
1 
2 
3 
4 
5 
[1]+ Done     { seq 10 > $f; } 

但如果我嘗試一個接一個讀取線,第一讀取成功,第二次讀取掛起。

$ { seq 5 > $f; } & 
[1] 2527 
$ read line < $f; echo $line 
1 
[1]+ Done     { seq 5 > $f; } 
$ read line < $f; echo $line 
[hangs here...] 

有人可以解釋這一點嗎?爲什麼我不能一一讀完所有5行?其餘數據發生了什麼?


我發現我可以讀行由行,如果我創建了一個文件描述符重定向FIFO:

$ { seq 5 > $f; } & 
[1] 2732 
$ exec 3<$f 
[1]+ Done     { seq 5 > $f; } 
$ read -u 3 line && echo $line || echo no more data 
1 
$ read -u 3 line && echo $line || echo no more data 
2 
$ read -u 3 line && echo $line || echo no more data 
3 
$ read -u 3 line && echo $line || echo no more data 
4 
$ read -u 3 line && echo $line || echo no more data 
5 
$ read -u 3 line && echo $line || echo no more data 
no more data 
$ exec 3<&- 

我還是不明白中間的情景。誰能解釋一下?


版本信息:

$ bash --version 
GNU bash, version 4.2.25(1)-release (i686-pc-linux-gnu) 
Copyright (C) 2011 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 

This is free software; you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. 
$ mkfifo --version 
mkfifo (GNU coreutils) 8.13 
Copyright (C) 2011 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. 

Written by David MacKenzie. 
+0

這可能與版本和bash vs ksh或??有關。你可以添加該信息嗎? (在任何情況下,我都不會知道答案;-()。本季度最有趣的問題! – shellter

+0

在OSX Mavericks和Ubuntu VirtualBox下的行爲完全一樣 –

+0

您的第三種情況不能被斥責 – devnull

回答

5

我猜會發生什麼情況是這樣的:

$ read line < $f打開FIFO讀,讀一行,然後關閉FIFO。一旦讀卡器關閉FIFO,寫卡器(seq 5 > $f)也會關閉。當你在下一次打開FIFO時沒有人寫入它,所以read塊。

隨着while FIFO開放讀取,直到while命令完成,允許寫入器發送更多的行到FIFO。

您可以使用lsof -p $$來驗證哪些文件在每個點都未打開。

+1

謝謝,我看到GNU info page說:「一個進程打開FIFO文件寫作,另一個閱讀「 - 暗示你說什麼。 –

2

這裏似乎有一些關於FIFO的疑惑。

當你說:

read line < $f 

它會打開FIFO,尋道,讀取和關閉後,用它做。無論您是閱讀一行還是整個數據都無關緊要。

因此,當您嘗試再次閱讀時,read一直在等待。

雖然它等待,試着說:

echo foo > $f 

,你會注意到read是成功的。

如果您在監視兩種情況下的系統調用,您會發現第二個read正在等待從FIFO讀取。

不確定你想要在這裏完成什麼,但你的觀察與預期的線很接近。