user623990
user623990

Reputation:

Named Pipe closing prematurely in script?

ls:

prwx------ 1 root root 0 fifo

write.sh:

#! /bin/bash
while true;
do
    echo "blah" > fifo
done

read.sh:

#! /bin/bash
while true;
do
    cat fifo
done

I have two terminals open, one running write.sh and another running read.sh. When I start write.sh first, it hangs (like it should). Then I go to the other terminal and start read.sh and it prints out "blah" a ton of times, then my write.sh stops. Why is my write script stopping? This is a little test I'm doing to try and understand pipes a little better because I'm going to be sending all my logs to a pipe so I can parse through them before writing them to a file.

What am I missing here?

Upvotes: 8

Views: 3049

Answers (2)

chad
chad

Reputation: 71

To get non-blocking piping behaviour you could also first open a read file descriptor and then a write file descriptor on fifo.

# cf. https://stackoverflow.com/questions/2776994/tee-a-pipe-asynchronously
(
rm -f fifo
mkfifo fifo
exec 3<fifo   # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!

(
exec 3>fifo  # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
    echo "blah" > fifo
done
)
#kill -TERM $bpid

See also: How do I use exec 3>myfifo in a script, and not have echo foo>&3 close the pipe?

Upvotes: 7

frankc
frankc

Reputation: 11473

There is a race condition here. Whichever script executes its inner loop command first (cat and echo respectively) will block and wait for the other script to execute its inner loop command. However, once the scripts syncronize, if the cat calls close() on the pipe before the echo executes its write() , the echo will be sent a SIGPIPE and your script will exit. You cannot write to a pipe that has been closed by its reader.

If you change your reader to tail -f instead of a while loop with cat, the reader stays alive rather than opens and closes the fifo in perpetuity and you should not get a SIGPIPE.

reference: man fifo

Upvotes: 6

Related Questions