vlad-ardelean
vlad-ardelean

Reputation: 7622

why does my (ubuntu 11.10 bash 4.2.10, x86_64 ) named pipe get clogged?

Step 1: I open a terminal and type

mkfifo mypipe
cat < mypipe

Step 2: I open another and type:

for elem in {1..100} ; do echo "$elem" > mypipe ; done

A random ammount of numbers get printed, the first script exits and the second hangs. Please share the wizdom. Ubuntu bug? If more info is needed please ask, i don't imagine anything relevant atm.

Thx, you guys are awesome.

Upvotes: 1

Views: 241

Answers (2)

Joni
Joni

Reputation: 111239

The way named pipes work is that when the writing process closes the pipe, the reading process receives an EOF. When cat sees the file has ended it stops reading and exits. Here bash seems to reuse the open file most of the time in the loop, rather than closing and reopening it in each run.

To ensure that the file is opened and closed exactly once you could write this:

(for elem in {1..100} ; do echo "$elem"  ; done) > mypipe

To get cat output exactly one number in each run you have to use the program /bin/echo rather than the built-in echo. This forces Bash to open and close the file in each run of the loop:

for elem in {1..100} ; do /bin/echo "$elem" > mypipe ; done

Upvotes: 1

Kevin
Kevin

Reputation: 56059

If there's a bug, it's that the cat side prints more than one. It's a race condition. What's happening there is that the cat is reading one line, before it can read the EOF afterwards (because they're separate writes) the echo writes the next line, so cat gets that, etc. Eventually, it seems, cat reaches an EOF before the echo redirect can write to the pipe. If you want to write all the numbers to the pipe at once, move the redirect to the end:

for elem in {1..100} ; do echo "$elem" done > mypipe 

Or better,

seq 100 > mypipe

If you want cat to get only one at a time... I'm not quite sure how you can do that easily (Though I believe I could hack it if necessary).

Upvotes: 1

Related Questions