I have this script verbatim:

#!/usr/bin/env bash

  while read line; do
    cat <<EOF

( echo; echo; echo 'du results:'; exit 0 ) > >(handle_json foo);

echo "zoom"

when I execute it, I get this:

enter image description here

I have to manually kill it with ctrl-C since it won't exit on it's own.

All I am trying to do is send the stdout of the subshell to the bash function so it JSON stringify the output (don't worry about escaping special chars for now).

Anybody know why this script doesn't exit on it's own?


this actually does what I want it to do:

( echo; echo; echo 'du results'; ) |  handle_json 'foo';

echo "zoom"

the above uses the pipe operator instead of redirection/process substition. I never expected the pipe operator to work here. Can someone explain why/how it works?

  • 2
    Are you sure it doesn't exit? It looks that bash is simply printing its prompt before the >(...) subshell has exited, which is to be expected with subshells which are run asynchronously. Press 'Enter' instead of '^C'. – mosvy Dec 22 '18 at 5:09
  • ... or put a sleep 1 at the end (just a debugging aid, not a good solution, as that's a race condition) to make sure the subshell finishes first. Then you'll see the prompt after 1s as expected. – derobert Dec 22 '18 at 5:12
  • Don't post images of text. Just copy-paste the text instead, it makes it easier for others to read it. – ilkkachu Dec 22 '18 at 9:04

As far as I can tell, your script did exit; it's just that the process substitution finished running and printing in the background after the outer shell printed its prompt.

A way to avoid this would be to simply pipe into your function instead of using > >(...):

( echo; echo; echo 'du results:'; exit 0 ) | handle_json foo

This works because, when writing cmd1 | cmd2, the two commands are started in parallel, with the standard output of cmd1 connected to the standard input of cmd2, and bash waits for both to have completed to consider the pipeline complete.

In contrast, cmd1 > >(cmd2) does nearly the same, except that bash does not wait for cmd2 to complete before going on with further commands (in this case, printing "zoom" and then exiting, letting the interactive bash print its prompt): if, by chance, cmd2 takes significantly more time to complete than cmd1, then the kind of surprising race condition you observed happens.

| improve this answer | |
  • thanks, I updated the OP right after I saw this answer! why does this work and the redirection/process substitution behave so strangely? – Alexander Mills Dec 22 '18 at 5:17
  • I will update my answer to address this additional question. – dhag Dec 22 '18 at 5:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.