我想让一个进程从一个从多个源接收数据的命名管道中读取:
$ mkfifo /tmp/p
Run Code Online (Sandbox Code Playgroud)
但我不知道如何让它始终如一地工作。
tty1 :
设置两个进程写入我的fifo;这两个都会阻止:
$ echo 'first' > /tmp/p; echo 'second' > /tmp/p
Run Code Online (Sandbox Code Playgroud)
tty2 :
从管道中读取:
$ cat /tmp/p
first
second
Run Code Online (Sandbox Code Playgroud)
如果我以相反的顺序执行上述操作,这仍然有效
当我有两个单独的命令想要从管道中出来时,我的问题就出现了:
第一个.sh
#!/bin/sh
echo 'first' > /tmp/p
Run Code Online (Sandbox Code Playgroud)
第二个.sh
#!/bin/sh
echo 'second' > /tmp/p
Run Code Online (Sandbox Code Playgroud)
tty1
$ sh first.sh; sh second.sh
Run Code Online (Sandbox Code Playgroud)
tty2
$ cat /tmp/p
first
Run Code Online (Sandbox Code Playgroud)
sh second.sh从我的第一个 tty执行将无限期地阻塞,直到从命名管道中读取其他内容。
来自http://linux.die.net/man/7/pipe:
如果所有引用管道写端的文件描述符都已关闭,则尝试从管道读取(2)将看到文件结束(读取(2)将返回 0)
因此,当echo退出 in 时first.sh,执行它的 shell 会关闭 的文件描述符/tmp/p,这意味着cat在我的第二个 TTY 中看到 EOF。
我如何用外壳解决这个问题?有没有办法在我的主控制脚本中保留对命名管道读取端的引用,以便在子外壳退出时它不会关闭?在实践中,我会将命名管道的路径传递给子外壳。我是否只需要让我的子 shell 输出到它们自己的标准输出并对其执行重定向?
我觉得这里缺少一些东西。除了这种情况外,对于我尝试做的所有事情,使用命名管道都很简单明了。
为什么不这样做:
{ echo foo; echo bar;} > /tmp/p
Run Code Online (Sandbox Code Playgroud)
如果您希望您的控制脚本让管道保持打开状态,您可以执行以下操作:
exec 3<> /tmp/p
Run Code Online (Sandbox Code Playgroud)
以读写模式打开命名管道是为了避免在管道尚未打开时阻塞。如果它还没有,那将实例化它。它至少适用于 Linux,但 POSIX 不保证。
或者(并且可移植):
: < /tmp/p & exec 3> /tmp/p
Run Code Online (Sandbox Code Playgroud)
然后,您还可以执行以下操作,而不是让每个进程打开命名管道:
cmd >&3
Run Code Online (Sandbox Code Playgroud)
最后,你会这样做:
exec 3>&-
Run Code Online (Sandbox Code Playgroud)
结束写作,让读者知道它已经完成了。
如果您需要相反的逻辑,请将所有<s更改为>s 并将<s更改为s >。