I want to have one process reading from a named pipe that receives data from multiple sources:
$ mkfifo /tmp/p
But I can't figure out how to get it to work consistently.
First Scenario - this works
tty1:
Set up two processes to write to my fifo; both of these will block:
$ echo 'first' > /tmp/p; echo 'second' > /tmp/p
tty2:
Read from the pipe:
$ cat /tmp/p
first
second
This still works if I execute the above in reverse order
My problem comes when I have two separate commands that I want to come out of the pipe:
Second Scenario - does not work
first.sh
#!/bin/sh
echo 'first' > /tmp/p
second.sh
#!/bin/sh
echo 'second' > /tmp/p
tty1
$ sh first.sh; sh second.sh
tty2
$ cat /tmp/p
first
The execution of sh second.sh
from my first tty will block indefinitely, until something else reads from the named pipe.
What I think is happening
From http://linux.die.net/man/7/pipe:
If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read(2) from the pipe will see end-of-file (read(2) will return 0)
So when echo
exits in first.sh
, the shell executing it closes the file descriptor for /tmp/p
, which means that cat
in my second TTY sees EOF.
How do I get around this with the shell? Is there a way to keep a reference to the read end of the named pipe around in my main controlling script, so that it doesn't get closed when sub-shells exit? In practise, I will be passing the path to the named pipe to the sub-shells. Do I need to just make my subshells output to their own stdout and perform a redirection on them?
I feel like there's something I'm missing here. Using named pipes has been simple and straightforward for everything I've tried to do aside from this case.
(first.sh;second.sh) > /tmp/p