2011-07-26 75 views
7

LS:命名管道在腳本中過早關閉?

prwx------ 1 root root 0 fifo 

write.sh:

#! /bin/bash 
while true; 
do 
    echo "blah" > fifo 
done 

read.sh:

#! /bin/bash 
while true; 
do 
    cat fifo 
done 

我有兩個終端開放,一個運行write.sh,而另一個運行read.sh。當我首先啓動write.sh時,它掛起(像它應該)。然後我去另一個終端,開始read.sh,它打印出"blah"一噸,然後我的write.sh停止。爲什麼我的寫腳本停止?這是一個小小的測試,我嘗試和理解管道更好一點,因爲我將把所有日誌發送到管道,以便在將它們寫入文件之前解析它們。

我在這裏錯過了什麼?

回答

5

這裏有一個競賽條件。無論哪個腳本首先執行其內部循環命令(分別爲cat和echo)都會阻止並等待另一個腳本執行其內部循環命令。但是,一旦腳本同步,如果cat在echo執行其write()之前調用管道上的close(),則會向SIG發送一個SIGPIPE,並且腳本將退出。您無法寫入已被其讀取器關閉的管道。

如果您將讀者更改爲tail -f而不是使用cat的while循環,讀者仍然活着,而不是永遠打開和關閉fifo,並且您不應該得到SIGPIPE。

參考:man fifo

+0

完美!謝謝。 – n0pe

5

要獲得非阻塞管道的行爲,你也可以先打開一個讀文件描述符,然後fifo寫文件描述符。

# cf. https://stackoverflow.com/questions/2776994/tee-a-pipe-asynchronously 
(
rm -f fifo 
mkfifo fifo 
exec 3<fifo # open fifo for reading 
trap "exit" 1 2 3 15 
exec cat fifo | nl 
) & 
bpid=$! 

(
exec 3>fifo # open fifo for writing 
trap "exit" 1 2 3 15 
while true; 
do 
    echo "blah" > fifo 
done 
) 
#kill -TERM $bpid 

參見:How do I use exec 3>myfifo in a script, and not have echo foo>&3 close the pipe?