6

I was trying to do something simple with a FIFO: read the lines, but not all at once, and it unexpectedly "did not work".

This is OK:

$ f=$(mktemp -u)
$ mkfifo $f
$ { seq 5 > $f; } &
[1] 2486
$ while read line; do echo $line; done < $f
1
2
3
4
5
[1]+  Done                    { seq 10 > $f; }

But if I try reading lines one-by-one, the first read succeeds and the 2nd read hangs.

$ { seq 5 > $f; } &
[1] 2527
$ read line < $f; echo $line
1
[1]+  Done                    { seq 5 > $f; }
$ read line < $f; echo $line
[hangs here...]

Can someone explain this? Why can't I read all 5 lines one-by-one? What happened to the rest of the data?


I discovered I can read line-by-line if I create a file descriptor to redirect the FIFO:

$ { seq 5 > $f; } &
[1] 2732
$ exec 3<$f
[1]+  Done                    { seq 5 > $f; }
$ read -u 3 line && echo $line || echo no more data
1
$ read -u 3 line && echo $line || echo no more data
2
$ read -u 3 line && echo $line || echo no more data
3
$ read -u 3 line && echo $line || echo no more data
4
$ read -u 3 line && echo $line || echo no more data
5
$ read -u 3 line && echo $line || echo no more data
no more data
$ exec 3<&-

I still don't understand the middle scenario. Can anyone explain?


Version info:

$ bash --version
GNU bash, version 4.2.25(1)-release (i686-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ mkfifo --version
mkfifo (GNU coreutils) 8.13
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David MacKenzie.
5
  • This could be related to version and bash vs ksh or ??. Can you add that info. (I won't know the answer in any case ;-( ). The most interesting question this quarter! Commented Apr 15, 2014 at 15:54
  • Exactly the same behaviour under OSX Mavericks and on a Ubuntu VirtualBox. Commented Apr 15, 2014 at 16:00
  • Your third scenario cannot be repro'd. Commented Apr 15, 2014 at 16:24
  • @devnull, really? what's your shell? Commented Apr 15, 2014 at 17:01
  • @glennjackman GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu) Commented Apr 15, 2014 at 17:22

2 Answers 2

6

I guess what happens is this:

$ read line < $f opens the FIFO for reading, reads one line, then closes the FIFO. Once the reader closes the FIFO on its side, the writer (seq 5 > $f) also closes. When you open the FIFO next time nobody writes to it at that point, so the read blocks.

With the while the FIFO is open for reading until the while command finishes, allowing the writer to send more lines to the FIFO.

You can use lsof -p $$ to verify what files are (not) open at each point.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I see the GNU info page says: "One process opens the FIFO file for writing, and another for reading" -- implying what you say.
4

It seems that there is some confusion about FIFO here.

When you say:

read line < $f

it'd open the FIFO, seek, read, and be done with it after closing. It doesn't matter whether you read a line or the entire data.

So when you attempt to read again, the read keeps waiting.

While it's waiting, try saying:

echo foo > $f

and you'd notice that the read is successful.

If you were monitoring the system calls being made in both the cases, you'd observe that the second read is waiting to read from the FIFO.

Not sure what you're trying to accomplish here but your observation is pretty much along expected lines.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.