This script:
#!/bin/bash
tmppipe=/tmp/temppipe
mkfifo $tmppipe
echo "test" > $tmppipe
cat $tmppipe
exit
does not terminate. I assume that the cat
command is waiting for an EOF
from the pipe; how do I send one?
This script:
#!/bin/bash
tmppipe=/tmp/temppipe
mkfifo $tmppipe
echo "test" > $tmppipe
cat $tmppipe
exit
does not terminate. I assume that the cat
command is waiting for an EOF
from the pipe; how do I send one?
No, it's
echo test > "$tmppipe" # BTW, you've got the quotes in the wrong places
that hangs. More precisely, it's the shell opening the pipe for writing before running echo
.
pipe
are inter-process communication mechanisms, they are to be used between processes running concurrently. Here, the open(WR_ONLY)
(>
) will block until another process does an open
in read mode.
echo test > "$tmppipe" &
cat < "$tmppipe"
will work because echo
and cat
run concurrently.
On Linux, you can get away with:
exec 3<> "$tmppipe" 4< "$tmppipe"
echo test >&3
exec 3>&-
cat <&4
That works because read+write open
s (<>
) on pipes don't block on Linux, and because the test\n
output by echo
is small enough to fit in the pipe, so you can do the write and the read sequentially.
It wouldn't work for a larger output like:
exec 3<> "$tmppipe" 4< "$tmppipe"
seq 100000 >&3
exec 3>&-
cat <&4
Because seq
would fill up the pipe (64kiB in current versions of Linux) and block until some other process reads data off that pipe, which will never happen because cat
won't run until seq
has finished.
Note that:
echo test 1<> "$tmppipe"
cat < "$tmppipe"
would not work either because the echo
command line would open the pipe, write test and then close the pipe (and then the system would destroy it as there's no file descriptor open to it anymore). So the next cat
command line would try to instantiate a new pipe (and block until something opens the fifo file for writing).
Turns out the answer is obvious - the pipe is being locked by echo
, and never reaches cat!
Pipes do not store data. When a process attempts to write to a pipe, the write cannot complete until there is something attached to the other end of the pipe, to read it.
A way to solve this particular example, is to use
echo "test" > $tmppipe &
to make the writing process run in the background. That way it sits there any waits, while the script continues, until it reaches the cat
and can complete.
$IFS
. Leaving a variable unquoted (unless you have a very good reason to) is bad practice leading to bugs and potential security issues. Quotes in shell have almost an opposite meaning as with other languages. – Stéphane Chazelas Jun 05 '15 at 10:52exec 3<> "$tmppipe"
). As you explained here,cat < "$tmppipe"
will never reachEOF
because the writer still exists. For it to work properly we need to open separate file descriptors for reading and writing, like so:exec 3<>"$tmppipe" 4>"$tmppipe" 5<"$tmppipe" 3>&-
and then close the write descriptor for the duration of reading:exec 4>&-; cat <&5; exec 4>"$tmppipe";
. – EvgenKo423 Feb 11 '21 at 14:00cat
terminates using a different approach. – Stéphane Chazelas Feb 11 '21 at 14:14cat <&4
is executed, I guess fd 4 gets closed (no need to performexec 4<&-
right?). But it is fd 0 ofcat
that receives the EOF status and closes. Is fd 4 closed as well because it is a duplicate of fd 0 ofcat
? Are there still two "synchronized" file descriptors here, or is it in fact the same object with two different labels (0 and 4, valid in their own respective context) pointing at that same object? I mean, why executingexec 3>&-
doesn't close fd 4? Because there is still data in the named pipe? – The Quark Nov 02 '21 at 16:00cat
are only getting closed whencat
exits. In the parent shell process, nothing changed with the fd 4. The pipe that was instantiated upon first opening the fifo file is still there, but there's nothing left in it (ascat
consumed everything), and there's no writer left, so a subsequent read on it will still return nothing (EOF). If, until that fd is closed something opens the fifo file, they will still land onto that same pipe. After, an open would instantiate a new pipe. – Stéphane Chazelas Nov 02 '21 at 17:42