我在 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
Run Code Online (Sandbox Code Playgroud)
然后,为了测试这个连接,我可以从一个新的终端 (B)
cd /tmp/IOdir
echo echo hello > pToB
Run Code Online (Sandbox Code Playgroud)
从第三个终端 (C)
cd /tmp/IOdir
(read myline && echo $myline) < bToP
Run Code Online (Sandbox Code Playgroud)
这就是我想要的。相同的 bash shell 保持活动状态,输出通过另一侧。将这种状态称为 X,以便我稍后参考。
从状态 X 向前
但是,现在,从这个状态 X 开始,我们不能再做同样的事情了。也就是说,如果我们从终端(B)
echo echo hello > pToB
Run Code Online (Sandbox Code Playgroud)
然后从终端 C
(read myline && echo $myline) < bToP
Run Code Online (Sandbox Code Playgroud)
然后在终端 C 什么也没有通过。 此外,如果我们再次这样做,从终端 B
echo echo hello > pToB
Run Code Online (Sandbox Code Playgroud)
bash shell 关闭。
我在状态 X 下可以做的首先是从终端 C
(read myline && echo $myline) < bToP
Run Code Online (Sandbox Code Playgroud)
然后从终端 B
echo echo hello > pToB
Run Code Online (Sandbox Code Playgroud)
在这种情况下, hello 在终端 C 出现,看起来我们又处于状态 X 中。所以我们基本上可以永远重复这个。现在这对于双向通信似乎已经足够了,但是我的程序是这样的,如果它请求这样的新行
(read myline && echo $myline)
Run Code Online (Sandbox Code Playgroud)
并且没有换行,它会“挂起”(就像bash,实际上我的意思是在程序中使用对bash的调用)。因此,此后无法将输入发送到 pToB,我无能为力。
问题
有没有办法在不使用 C 进行太多编程的情况下进行设置?有没有办法在不使用两个命名管道的情况下更优雅地做到这一点?是什么导致管道在一种情况下关闭,而在另一种情况下不关闭?
编辑
从维基百科的这个页面,我们有
全双工(双向)通信通常需要两个匿名管道。
一方面,似乎至少我有正确数量的管道。另一方面,我使用的是命名管道,而不是匿名管道。所以也许这将是困难的/不可能的。
此外, mkfifo gnu/linux source可能是根据 mknod gnu/linux source 定义的,这也是一个 unix 命令。但我不确定是否可以从中学到很多东西。
这里介绍一下C中的pipe,包括pip的linux源码。也许这可以告诉我们为什么管道会关闭,如果确实发生了这种情况。
这是一个有关防止fifos关闭的相关问题。我尝试将管道连接到后台睡眠进程,就像在回答 tere 中所做的那样,但这没有帮助。
至于原因,使用strace
.
tail -f | strace bash >> foo
Run Code Online (Sandbox Code Playgroud)
第二个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 +++
Run Code Online (Sandbox Code Playgroud)
因此,第二次尝试写入 hello\n 时,它会收到损坏的管道错误;这就是为什么你无法读取 hello (它从未被写入),并且 bash 退出,所以这就是结束。
我猜你必须使用一些东西来保持管道打开。
这个怎么样?
(while read myline; do echo $myline; done) < pToP
Run Code Online (Sandbox Code Playgroud)
有关更多背景信息,man 7 pipe
可能相关,它描述了管道周围的各种错误情况。
归档时间: |
|
查看次数: |
6846 次 |
最近记录: |