The process reading from a named pipe will normally terminate when the process writing to the pipe finishes writing (sends an EOF). In certain situations you may have different processes writing intermittently to the pipe, and want a single process to continuously read from the pipe. To do this you can set up a 'dummy' writer that opens the pipe but doesn't write to it:

$ mkfifo myPipe
$ cat > myPipe &

The dummy writer keeps the named pipe open — without feeding data into it or ever closing. The reader process is thus able to receive input from all of the (other) legitimate writers without terminating and having to be respawned.

I have seen some folks use exec 3> instead of cat as a way to keep the named pipe open.

$ mkfifo myPipe
$ cat < myPipe &
[1] 10796
$ exec 3> myPipe
$ echo "blah" > myPipe

This approach seems to work, and you don't have a dummy writer in the background to worry about (or clean up), so I like it. The problem is that I don't really understand it.

How is exec 3> accomplishing the task of keeping the named pipe open without an actual file to be executed, or a visible (background) process, and are there any downsides to this approach?

(I know that it must ultimately be opening the named pipe's input file descriptor for writing, so I'm specifically interested in what the exec 3 part of exec 3> is doing.)

  • 1
    As an aside, instead of echo "blah" > myPipe, you could also echo "blah" >&3 too, because echo inherits the open file descriptor 3 from the shell. – Niko Gambt Jan 26 at 6:43
  • @NikoGambt So is file descriptor 3 in existence before the code even runs — and we're just making use of it — or does it come into existence as a result of the code running? – Tim Jan 26 at 6:48
  • 1
    Fd 3 gets redirected to myPipe the moment the shell executes exec 3> myPipe. – Niko Gambt Jan 26 at 6:50

You're parsing it wrong; it's exec and 3>fifo not exec 3 and >fifo. exec without a command applies any redirection to the main shell, and the > redirection can take a file descriptor argument (as in 3>) instead of the implicit 1 (stdout).

As to its downsides, the opened file descriptor will be passed down to subprocesses/subshells, and unless closed explicitly (with exec 3>&-) in each of them, will cause any reader at the other end of the pipe not to get an EOF until all those subprocesses have exited.

Yet another trick to keep a pipe open, and which will also cause it not to block on opening it is to open it in read-write mode:

mkfifo /tmp/fifo
(exec 1<>/tmp/fifo; echo tee; sed 's/e/o/g; 1q' <&1 >&2)
  • So exec merely serves to redirect stream 3 from the current shell into the named pipe? If that's the case, what is stream 3? 0=stdin, 1=stdout, 2=stderr, 3=? Or can 3 be any arbitrary number except for [0,1,2]? – Tim Jan 26 at 5:21
  • 1
    3 will be a new stream, unless it's already opened. It's the responsibility of the script writer to make sure fd 3 isn't already in use for other purposes. It can be any number from 0-9 in most shells, and 0-1023 in bash (the latter may be system-dependent). And there's no exception for 0,1,2: 0>/tmp/foo is perfectly fine, even if its effects may be unexpected ;-) – pizdelect Jan 26 at 5:33
  • I'm not a big fan of 'unexpected'. :) To avoid the inheritance of FD 3 (or whatever) becoming problematic/messy, would it make sense to limit further commands and use the script that sets up the named pipe to also launch and 'become' the persistent reader process? As in: exec /path/to/reader 3> myPipe ? – Tim Jan 26 at 7:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.