为什么这个带有 FIFO 管道的脚本不会终止?

Ben*_*ird 8 bash pipe shell-script fifo

这个脚本:

#!/bin/bash
tmppipe=/tmp/temppipe
mkfifo $tmppipe
echo "test" > $tmppipe
cat $tmppipe
exit
Run Code Online (Sandbox Code Playgroud)

不终止。我假设该cat命令正在等待EOF来自管道的一个;我怎么寄?

Sté*_*las 11

不,它是

echo test > "$tmppipe" # BTW, you've got the quotes in the wrong places
Run Code Online (Sandbox Code Playgroud)

挂了。更准确地说,它是 shell 在运行之前打开管道进行写入echo

pipe是进程间通信机制,它们用于并发运行的进程之间。在这里,open(WR_ONLY)( >) 将阻塞,直到另一个进程open进入读取模式。

echo test > "$tmppipe" &
cat < "$tmppipe"
Run Code Online (Sandbox Code Playgroud)

将工作,因为echocat同时运行。

在 Linux 上,你可以逃脱:

exec 3<> "$tmppipe" 4< "$tmppipe"
echo test >&3
exec 3>&-
cat <&4
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为管道上的read+write opens ( <>) 在 Linux 上不会阻塞,并且因为test\n输出 byecho足够小以适合管道,因此您可以按顺序进行写入和读取。

它不适用于更大的输出,例如:

exec 3<> "$tmppipe" 4< "$tmppipe"
seq 100000 >&3
exec 3>&-
cat <&4
Run Code Online (Sandbox Code Playgroud)

因为seq会填满管道(在当前版本的 Linux 中为 64kiB)并阻塞,直到其他进程从该管道读取数据,这永远不会发生,因为在完成cat之前不会运行seq

注意:

echo test 1<> "$tmppipe"
cat < "$tmppipe"
Run Code Online (Sandbox Code Playgroud)

也不会工作,因为echo命令行会打开管道,编写测试,然后关闭管道(然后系统会销毁它,因为不再有文件描述符对它打开)。因此,下一个cat命令行将尝试实例化一个新管道(并阻塞,直到打开 fifo 文件进行写入)。