1

If there is nothing in a named pipe and I do:

cat my_named_pipe

it will wait until data arrives. Is there a flag I can use to exit immediately if there is no data to be read? Or perhaps a command other than cat that I can use?

I also tried:

read val < "$my_named_pipe";

but this also waits for the next chunk of data - I don't want to wait if the fifo is empty.

  • Hmmm... Unfortunately, read in bash with a timeout (its -t option) doesn't seem to cut it. – Kusalananda Jun 4 at 17:36
  • @Kusalananda, it's the open() (the redirection), not the read() that blocks when there's no writer to the pipe. – Stéphane Chazelas Jun 4 at 17:37
  • @StéphaneChazelas Ah, yes, that makes sense. – Kusalananda Jun 4 at 17:37
3

To prevent cat from hanging in the absence of any writer (in which case it's the opening of the fifo, not reading from it, that hangs), you can do:

cat 0<> "$my_named_pipe" <"$my_named_pipe"

The first redirection opens in read+write mode which on most systems doesn't block and instantiates the pipe even if there's no writer nor reader already. Then the second open (read-only this time) would not block because there is at least one writer now (itself).

The 0 is only needed in recent versions of ksh93 where the default fd for <> changed from 0 to 1.

Also, in ksh93, that would not work when cat is the shell builtin, like when ksh93 is called when /opt/ast/bin is ahead of /bin in $PATH or after a call to builtin cat as upon the <"$my_named_pipe", (I guess) ksh93 saves the previous target of stdin on a separate file descriptor which would hold the pipe open. You can work around that by writing it instead:

cat 3<> "$my_named_pipe" <"$my_named_pipe" 3<&-

(which you might also argue conveys the intention more clearly)

Note that that <> on the pipe would also unlock other readers to the fifo.

If there were some writers, cat would still have to read all their output and wait until they have closed their end of the pipe. You could open the pipe in non-blocking mode, like with GNU dd's:

dd bs=64k if="$my_named_pipe" iflag=nonblock status=noxfer

Which would only read from the pipe as long as there's some data in it, and exit with a

dd: error reading 'fifo': Resource temporarily unavailable

error when there's no more, and not unlock other readers, but that means you could miss some of the writers output if they are slower to write to the pipe than you (dd) are to read it.

Another approach could be to timeout when there's been no input in a while, for instance by using socat's -T option:

socat -u -T1 - - 0<> "$my_named_pipe" <"$my_named_pipe"

Which would exit if there's not been anything coming from the pipe in one second.

  • seems to work, but I have no idea why - the named pipe should pre-exist, so I don't need to instantiate it? – Alexander Mills Jun 4 at 17:46
  • 1
    nb: that trick still relies on all the other writers to close the pipe in order for the cat to return. If another process has opened the pipe with eg. exec 7>fifo and keeps the fd 7 open, the cat <>fifo <fifo will still block, but not when trying to open the pipe, but when trying to read more data from it. – mosvy Jun 4 at 18:11
  • @mosvy, thanks. See edit where I've added more notes and details. – Stéphane Chazelas Jun 5 at 5:16

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.