Q:

Bash pipeline execution

The netcat manpage indicates that, in the absence of the -c and -e options, a shell can be served via nc using the following commands.
$ rm -f /tmp/f; mkfifo /tmp/f
$ cat /tmp/f | /bin/sh -i 2>&1 | nc -l 127.0.0.1 1234 > /tmp/f

Now, as I understand it, both reads and writes from fifos are blocking operations. For example, if I run
$ mkfifo foo
$ cat foo

bash will block, because nothing has been written to foo. How does the pipeline in the example from the nc manpage not block? I assume I am misunderstanding how pipelines are executed.

A:

All the commands in the pipeline run concurrently, not sequentially. So cat /tmp/f will indeed block, but /bin/sh and nc will still be started while that happens. nc will write to the FIFO when a client connects to the port and sends a command, and this will allow cat to unblock.

A:

The pipe character in bash does notthing esle then connecting the output stream of the first command to the input stream of the second. echo "123" | cat is essentially the same as cat < <(echo 123) (the latter does only start one subshell though while the first starts one for each command, but this can be ignored here - plus, it's a bashism and does not work in sh).
$ mkfifo foo
$ cat foo

Does indeed block - but not freeze. The moment any other program writes anything to foo, cat will display it.
WHat you are doign in your netcat call is essentially create a cicrle: anything written into the FIFO will be displayed by cat, and, as cat is connected to sh sent to the latter. sh will then execute the code (as sh just executes anything written to it's input stream) and send the output to nc. nc will sent it to the client.
ANything the client sends to nc will be written into the FIFO - and our circle is complete.
The mistake you made (I think) is to assume the second process of a pipe only reads the data once, not continuously, and therefore has to wait for the first process to end. This is not true, because every process in a pipeline is started in a shubshell, so they all run intependent of each other.

You should also be able to change the order of all commands in your pipeline. As long as the first one reads from the FIFO and the last one writes to it (to complete the circle), it should work.

