我在 OSX 上,使用 bash,试图理解管道。我希望让程序与 bash shell 进行两个方向的通信。我想以这样的方式进行设置,使其始终是相同的 shell,以便我可以 cd 到某个目录并且 bash 会记住(而不是一直使用新的 bash shell)。
到目前为止我所尝试的是这样的。从新终端 (A) 执行
mkdir /tmp/IOdir
cd /tmp/IOdir
mkfifo pToB
mkfifo bToP
tail -f -1 pToB | bash >> bToP
然后,为了测试此连接,我可以从新终端 (B)
cd /tmp/IOdir
echo echo hello > pToB
从第三航站楼 (C)
cd /tmp/IOdir
(read myline && echo $myline) < bToP
这就是我想要的行为。相同的 bash shell 保持活动状态,并且输出从另一端通过。称这种情况为X,以便我以后可以参考。
从状态 X 继续
然而,现在,从这个状态X开始,我们不能再做同样的事情了。也就是说,如果我们从终端 (B) 进行
echo echo hello > pToB
然后从航站楼 C
(read myline && echo $myline) < bToP
然后航站楼 C 就什么也没有通过。此外,如果我们再次这样做,从航站楼 B
echo echo hello > pToB
bash shell 关闭。
我在 X 状态下可以做的事情是首先从 C 航站楼做
(read myline && echo $myline) < bToP
然后从 B 航站楼出发
echo echo hello > pToB
在这种情况下,终端 C 发出 hello 信号,看起来我们再次处于状态 X。所以我们基本上可以永远重复这个。现在这对于双向通信来说似乎足够了,但是我的程序是这样的,如果它请求像这样的新行
(read myline && echo $myline)
并且没有新行,它会“挂起”(就像bash一样,实际上我的意思是在程序中使用对bash的调用)。因此,此后无法将输入发送到 pToB,我无能为力。
问题
有没有一种方法可以在不使用太多 C 语言编程的情况下进行设置?有没有一种方法可以在不使用两个命名管道的情况下更优雅地做到这一点?是什么导致管道在一种情况下关闭,而在另一种情况下不关闭?
编辑
从维基百科上的此页面, 我们有
全双工(双向)通信通常需要两个匿名管道。
一方面,看起来至少我有正确数量的管道。另一方面,我使用命名管道,而不是匿名管道。所以也许这会很难/不可能。
此外mkfifognu/linux 源代码可能是根据 mknod 定义的gnu/linux 源代码,这也是一个unix命令。但我不确定是否可以从中学到很多东西。
这里是对C语言管道的介绍,包括管道的linux源码。如果确实发生了这种情况,也许这可以告诉我们为什么管道会关闭。
这里是一个关于防止 fifo 关闭的相关问题。我尝试将管道连接到后台睡眠进程,就像在答案中所做的那样,但这没有帮助。
答案1
至于原因,使用strace
.
tail -f | strace bash >> foo
第二个echo echo hello > pToB
给了我这个:
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "e", 1) = 1
read(0, "c", 1) = 1
read(0, "h", 1) = 1
read(0, "o", 1) = 1
read(0, " ", 1) = 1
read(0, "h", 1) = 1
read(0, "e", 1) = 1
read(0, "l", 1) = 1
read(0, "l", 1) = 1
read(0, "o", 1) = 1
read(0, "\n", 1) = 1
write(1, "hello\n", 6) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=3299, si_uid=1000} ---
+++ killed by SIGPIPE +++
因此,第二次尝试写入 hello\n 时,它会收到损坏的管道错误;这就是为什么你无法读取 hello (它从未被写入),并且 bash 退出,所以这就是结束。
我猜你必须使用一些东西来保持管道打开。
这个怎么样?
(while read myline; do echo $myline; done) < pToP
有关更多背景信息,man 7 pipe
可能相关,它描述了管道周围的各种错误情况。
答案2
作为frostschutz答案的附录,请考虑下表
我们第一次尝试将 hello 发送到 bToP 时,它会被阻止,直到还有一个 fifo 读取器。第二次,读者发回 SIGPIPE 信号,该信号终止 bash。即使我们可以忽略这一点,之后我们也可能会遇到 EPIPE 错误。
我认为我正在尝试做的事情是不可能的。我的应用程序无法“同时读写”。我想我必须制作一个能够保持管道两侧打开的中间程序。