Problem with pipes. Pipe terminates when reader done
Solution 1
As for the cause, use strace
.
tail -f | strace bash >> foo
The second echo echo hello > pToB
gives me then this:
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 +++
So, the second time it tries to write hello\n, it gets a broken pipe error; that's why you can't read hello (it was never written), and bash quits so that's the end of it.
You'd have to use something that keeps the pipe open, I guess.
How about this?
(while read myline; do echo $myline; done) < pToP
For more background information, man 7 pipe
may be relevant, it describes the various error cases around pipes.
Solution 2
As an addendum to frostschutz answer, consider the following table
The first time we try to send hello into the bToP, it gets blocked until there is also a reader for the fifo. The second time we, the reader sends back a SIGPIPE signal, which terminates bash. Even if we could ignore that, we would probably run into the EPIPE error after that.
I think what I am trying to do is impossible. My application cannot "read and write at the same time". I think I will have to make an intermediate program capable of keeping both sides of the pipe open.
Related videos on Youtube
Trooper
Updated on September 18, 2022Comments
-
Trooper over 1 year
I am on OSX, using bash, trying to make sense of pipes. I wish to let a program communicate in two directions with a bash shell. I want to set this up in such a way that this is always the same shell, so that I can cd to some directory and bash will remember (rather than using a new bash shell all the time).
What I have tried so far is this. From a new terminal (A), do
mkdir /tmp/IOdir cd /tmp/IOdir mkfifo pToB mkfifo bToP tail -f -1 pToB | bash >> bToP
Then, to test this connection, I can do, from a new terminal (B)
cd /tmp/IOdir echo echo hello > pToB
and from a third terminal (C)
cd /tmp/IOdir (read myline && echo $myline) < bToP
This behaves how I want. The same bash shell stays active, and the output comes through on the other side. Call this state of affairs X, so that I can refer later to it.
Onward from state X
However, now, from this state X, we cannot do the same thing again. That is, if we do from terminal (B)
echo echo hello > pToB
and then from terminal C
(read myline && echo $myline) < bToP
Then nothing comes through in terminal C. Moreover, if we again do, from terminal B
echo echo hello > pToB
The bash shell closes.
What I could have done in state X was first do, from terminal C
(read myline && echo $myline) < bToP
and then from terminal B
echo echo hello > pToB
In this case hello comes through at terminal C, and it seems like we are in state X again. So we can basically repeat this forever. Now this might seem sufficient for two way communication, but my program is such that if it requests a new line like this
(read myline && echo $myline)
and there is no new line, it will "hang" (just like bash, in fact I mean to use a call to bash in the program). It is therefore not able to send input to pToB after that and there is nothing I can do.
Questions
Is there a way to set this up without doing too much programming in C? Is there a way to do this more elegantly without using two named pipes? What is causing the pipe to close in one scenario, and not in the other?
Edits
From this page on wikipedia, we have
Full-duplex (two-way) communication normally requires two anonymous pipes.
On one hand, it seems at least I have the right number of pipes. On the other, I am using named pipes, not anonymous ones. So maybe this will be hard/impossible.
Furthermore mkfifo gnu/linux source is likely defined in terms of mknod gnu/linux source, which is also a unix command. But I'm not sure if much can be learned from that.
Here is an introduction to pipes in C, including the linux source of pipe. Maybe that can tell us why a pipe gets closed, if that is indeed what happens.
Here is a related question about preventing that fifos get closed. I tried tying the pipes to background sleeping processes as was done in an answer tere but that didn't help.
-
Admin almost 11 yearsWelcome to unix.stackexchange.com! Thank you for including lots of details in your question. Make sure to stop by the help page.
-
Trooper almost 11 years@EvanTeitelman thanks for the warm welcome. I looked at the help page. I also edited my question a bit. Do you know if it is possible to add invisible/comment text to a question? For example, I was not allowed to put more links in here. I figured maybe somebody could edit and put them in for me. Anyway it does not matter in this case, I don't think people care about the source of mknod :P.
-
Admin almost 11 yearsYou can use HTML-style comments:
<!-- comment text -->
. If you add the links as comments, I'll make them real links for you. -
Trooper almost 11 years@EvanTeitelman thank you. I have edited the question, but maybe the other brackets ( () and [] ) we interfering. It would be nice if it looked like (gnu/linux source), with the brackets.
-
Trooper almost 11 years@EvanTeitelman this is fine too, thanks again :).
-
Mel Boyce almost 11 yearsCan bash hang off / on to a domain socket?
-
Trooper almost 11 years@MelBoyce I do not know, I would think so. But a domain socket is not exactly the same as I fifo it seems, though it seems very similar.
-