1

I just came across the following script while browsing this question:

rm -f out
mkfifo out
trap "rm -f out" EXIT
while true
do
  cat out | nc -l 1500 > >( # parse the netcat output, to build the answer redirected to the pipe "out".
    export REQUEST=
    while read line
    do
      line=$(echo "$line" | tr -d '[\r\n]')

      if echo "$line" | grep -qE '^GET /' # if line starts with "GET /"
      then
        REQUEST=$(echo "$line" | cut -d ' ' -f2) # extract the request
      elif [ "x$line" = x ] # empty line / end of request
      then
        HTTP_200="HTTP/1.1 200 OK"
        HTTP_LOCATION="Location:"
        HTTP_404="HTTP/1.1 404 Not Found"
        # call a script here
        # Note: REQUEST is exported, so the script can parse it (to answer 200/403/404 status code + content)
        if echo $REQUEST | grep -qE '^/echo/'
        then
            printf "%s\n%s %s\n\n%s\n" "$HTTP_200" "$HTTP_LOCATION" $REQUEST ${REQUEST#"/echo/"} > out
        elif echo $REQUEST | grep -qE '^/date'
        then
            date > out
        elif echo $REQUEST | grep -qE '^/stats'
        then
            vmstat -S M > out
        elif echo $REQUEST | grep -qE '^/net'
        then
            ifconfig > out
        else
            printf "%s\n%s %s\n\n%s\n" "$HTTP_404" "$HTTP_LOCATION" $REQUEST "Resource $REQUEST NOT FOUND!" > out
        fi
      fi
    done
  )
done

Yet, I am still struggling to "decode" the syntax found in the 6th line, namely: > >

On one hand I would expect that there was not any blank space in-between > characters - as soon as I remove that blank space the script simply does not run anymore.

On the other hand I would not expect to find a redirection being sent to another process since in those cases a simple pipe would be the perfect fit. Actually, I replaced > > by | and the script ran smoothly.

Long story short, could you explain to me:

  1. Why is the blank space in-between > mandatory ?
  2. Which is the semantics of the command > > ? (A redirection I guess !)
  3. Why not to use a pipe instead of a redirection ?

Thank you in advance.

Community
  • 1
  • 1
utxeee
  • 953
  • 1
  • 12
  • 24

1 Answers1

3

The syntax is not > >, but > >(). That's a process substitution. Basically bash creates a named pipe with standard input on the process inside the pipe available as effectively a file to the process outside.

Whatever gets redirected to the pipe will be read by the process inside the pipe as standard input. In your case, that process is itself a multiline bash script.

If you replace the > > with a pipe, your script will work mostly the same, but you're cheating a bit. Again, the actual syntax isn't > >, but > >(), so when you change it to | () you're actually piping to an explicit subshell (the part inside the parentheses). Without that subshell you have

cat out | nc -l 1500 | export REQUEST=
    ...

export doesn't read standard input, and the rest of the script will not be part of the pipeline, so it will not behave consistently.

kojiro
  • 74,557
  • 19
  • 143
  • 201
  • kojiro, thank you for the clarification regarding the process substitution. Yet, I am not completely convinced in regards to question 3 because I could simply group all those commands starting at the export keyword with curly brackets in order to stop piping to an explicit subshell. My point here is that I do not see any advantage in using the process substitution instead of a pipe... – utxeee Feb 01 '15 at 13:11
  • I'm not convinced there is any advantage. A pipe to curly braces, or an explicit subshell, or a process substitution will ask effectively create a subshell. The main reason to choose one over the other is to choose explicitly where the subshell is. In this case the same chunk of code would be in a subshell regardless. – kojiro Feb 01 '15 at 18:16