The problem in approach 3 is that the FIFO pipe
then has 2 writers: The bash script (because you have opened it read/write by using exec 3<>
) and the sub-shell running foo
. You'll read EOF when all writers have closed the file descriptor. One writer (the sub-shell running foo
) will exit fairly quickly (after roughly 1s) and therefore close the file descriptor. The other writer however (the main shell) only closes the file descriptor when it'd exit as there's no closes of file descriptor 3
anywhere. But it can't exit because it waits for the cat
to exit first. That's a deadlock:
cat
is waiting for an EOF
- the EOF only appears when the main shell closes the fd (or exits)
- the main shell is waiting for
cat
to terminate
Therefore you'll never exit.
Case 2 works because the pipe only ever has one writer (the sub-shell running foo
) which exits very quickly, therefore an EOF will be read. In case 1, there's also only ever one writer because you open fd 3 read-only (exec 3<
).
EDIT: Remove nonsense about case 4 not being correct (see comments). It's correct because the writer can't exit before the reader connects because it'll also be blocked when opening the file when the reader isn't opening yet. The newly added case 4 is unfortunately incorrect. It's racy and only works iff foo
doesn't terminate (or close the pipe) before exec 3<pipe
runs.
Also check the fifo(7)
man page:
The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process. The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.