Problem with pipes. Pipe terminates when reader done

6,952

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

enter image description here

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.

Share:
6,952

Related videos on Youtube

Trooper
Author by

Trooper

Updated on September 18, 2022

Comments

  • Trooper
    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
      Admin almost 11 years
      Welcome to unix.stackexchange.com! Thank you for including lots of details in your question. Make sure to stop by the help page.
    • Trooper
      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
      Admin almost 11 years
      You can use HTML-style comments: <!-- comment text -->. If you add the links as comments, I'll make them real links for you.
    • Trooper
      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
      Trooper almost 11 years
      @EvanTeitelman this is fine too, thanks again :).
    • Mel Boyce
      Mel Boyce almost 11 years
      Can bash hang off / on to a domain socket?
    • Trooper
      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.