How to cat named pipe without waiting
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.