2
#!/bin/bash
rm out
mkfifo out
nc -l 8080 < out | while read line
do
    echo hello > out   
    echo $line
done

If I browse to the IP of the machine this script is running on (using port 8080), I would expect to see the word 'hello' and then on the machine running the script, I would expect it to output lines from the request.

However, nothing happens. The browser gets no response, and nothing is output to the server's terminal.

Why doesn't it work, and what can I modify to make it work? I want to keep it to simple pipes, I don't want to use process substitution or anything like that.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Cameron Ball
  • 771
  • 2
  • 8
  • 21
  • The `echo` doesn't happen until after `nc` reads something. – Mikel Aug 19 '14 at 05:13
  • Can you elaborate further? This, for example, works: nc -l 8080 < out | echo test > out (i.e., I see "test" in my browser) – Cameron Ball Aug 19 '14 at 05:20
  • 1
    Just run the `while` loop by itself and it will hang waiting for input. Your `nc -l 8080 < out` line isn't producing any input when it is piped to this `while` loop which is why it doesn't do anything. It is waiting for input which never arrives. – Warwick Aug 19 '14 at 06:10
  • Gotcha, so how can I achieve what I want then? – Cameron Ball Aug 19 '14 at 06:15
  • Take a look at [this](http://unix.stackexchange.com/questions/39362/using-in-out-named-pipes-for-a-tcp-connection) and see if it helps. – Warwick Aug 19 '14 at 06:42

1 Answers1

1

The redirection < out causes the named pipe to be opened for reading. This blocks as long as no process has the pipe open for writing. Meanwhile, the right-hand side of the pipeline is blocking in the read command, waiting for nc (which hasn't started yet) to output something through the pipe. It's a deadlock.

To allow the script to proceed, make sure that the named pipe is open for writing and for reading independently. For example:

nc -l 8080 < out | while read line
do
    echo hello >&3
    echo "$line"
done 3>out

or

nc -l 8080 < out | {
  exec 3>out
  while read line
  do
    echo hello >&3
    echo "$line"
  done
}

Note that something like this wouldn't work, because nc would see that its input is closed after reading 0 bytes, and subsequent writes would block waiting for the named pipe to be opened again for reading:

nc -l 8080 < out | {
  : >out
  while read line
  do
    echo hello >out
    echo "$line"
  done
}
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175