2011-07-26 53 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?