Reputation: 3258
I'm having a hard time understanding named pipes. I have the following script:
#!/bin/bash
function a_or_b {
echo 'func begins'
while true; do
echo 'loop begins'
read -s -n 1; echo $?
case $REPLY in
'a') return 0 ;;
'b') return 1 ;;
esac
done
echo 'func ends'
}
mkfifo pipe
a_or_b <pipe &
Now what I was expecting this script to do is:
a_or_b
and therefore print func begin
loop begins
pipe
(as I have not written anything to pipe
) and therefore print 1
as $?
When running this script though I get no output and my terminal simply prints its next prompt.
If I redirect an echo into pipe
before calling a_or_b
:
...
mkfifo pipe
echo 'x' > pipe
a_or_b <pipe &
... the script doesn't stop running and I can keep entering characters (including a
and 'b') in the terminal to no effect. So I have to end the script using ^C.
If I redirect an echo into pipe
after calling a_or_b
:
...
mkfifo pipe
a_or_b <pipe &
echo 'x' > pipe
... I get the following output:
func begins
loop begins
0
loop begins
0
loop begins
1
loop begins
1
loop begins
1
This is basically the behavior I expected from not echoing anything to pipe
. The function begins, goes into the loop, reads the x
and \n
characters from the echo
(corresponding to the two 0
s in the output) and then keeps looping forever while failing to read any characters. And if I echo a
or b
into the pipe, the function ends.
What is causing all of these different behaviors?
Upvotes: 2
Views: 999
Reputation: 361605
a_or_b <pipe &
Redirections are processed before starting commands. The shell blocks trying to open pipe
for reading. From the mkfifo(3) man page:
Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa.
The shell can't proceed until another process opens the FIFO for writing. Only then will it finish setting up the redirection and actually call a_or_b
.
echo 'x' > pipe
a_or_b <pipe &
Unfortunately this has the same, but inverse problem. The shell can't proceed past the > pipe
redirection until another process opens the FIFO for reading. It never gets to the echo
nor the second line that would read from the pipe.
a_or_b <pipe &
echo 'x' > pipe
Hopefully you can now see why this version works. The background shell tries to read from the pipe and blocks. The foreground shell, a separate process, writes to it. Aha! Two processes have opened the pipe, one for reading and one for writing. They can now both proceed. The birds sing and everybody is happy.
Upvotes: 4