脚本中的命名管道过早关闭?

8

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停止了。为什么我的写脚本会停止?这是我正在做的一个小测试,以便更好地理解管道,因为我将发送所有日志到管道中,以便在将它们写入文件之前对它们进行解析。

我错过了什么吗?

2个回答

7
为了获得非阻塞的管道行为,您可以先在fifo上打开读文件描述符,然后再打开写文件描述符。
# cf. https://dev59.com/C03Sa4cB1Zd3GeqPwp6E
(
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

参见:如何在脚本中使用exec 3> myfifo,而不让echo foo>& 3关闭管道?


6
这里存在竞态条件。无论哪个脚本先执行其内部循环命令(cat和echo分别),都会阻塞并等待另一个脚本执行其内部循环命令。然而,一旦脚本同步,如果cat在echo执行其write()之前调用close()关闭管道,则echo将收到一个SIGPIPE信号,你的脚本将退出。你不能向已被读者关闭的管道写入数据。
如果你将读取器更改为tail -f而不是使用cat的while循环,读取器将保持活动状态而不是永久打开和关闭fifo,因此你不应该收到SIGPIPE信号。
参考:man fifo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接