Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using mkfifo in a shell script

Tags:

bash

shell

mkfifo

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.
like image 253
glenn jackman Avatar asked Apr 15 '14 15:04

glenn jackman


People also ask

What does mkfifo command do?

The mkfifo command creates FIFO special files specified by the File parameter, in the order specified.

Is mkfifo a system call?

A FIFO file is a special kind of file on the local storage which allows two or more processes to communicate with each other by reading/writing to/from this file. A FIFO special file is entered into the filesystem by calling mkfifo() in C.

How do I create a named pipe in Linux?

We can use mkfifo or mknod command to create a named pipe. A pipe is a structure which one end can send message and the other can consume it.

What does trap do in Bash?

If you've written any amount of bash code, you've likely come across the trap command. Trap allows you to catch signals and execute code when they occur. Signals are asynchronous notifications that are sent to your script when certain events occur.


1 Answers

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.

like image 173
mustaccio Avatar answered Sep 24 '22 15:09

mustaccio