Redirecting process substitutions
If you intend to use bash redirections and process substitutions together, they might look cryptic.
In this article I would like to debunk that confusion a little bit.
Let's start with
$ > >(echo fine) 2> >(echo error)
fine
Here the effect is the same as echo error | echo fine.
Next
$ > >(echo fine) 2> >(echo error >&2)
fine
error
Here the effect is the same as echo fine; echo error >&2. Because they are disjointed (none of them depend on the other), they are not piped. There is no recursion because echo error >&2 just prints to terminal.
If we try the other way around
$ 2> >(echo error) > >(echo fine >&2)
error
This is the same as { echo fine >&2; } 3>&1 1>&2 2>&3 | echo error.
If they are disjointed
$ 2> >(echo error) > >(echo fine)
error
fine
This is the same as echo error; echo fine.
What if we include a command to be run?
$ whoami > >(cat) 2> >(echo error)
error
logan
This is the same as { echo error & whoami; } | cat. Well, more exactly can be thought of as { echo error & whoami 2>/dev/null; } | cat.
Another example
$ whoami > >(sed 's/^/processed: /') 2> >(echo error)
processed: error
processed: logan
You could think of this as { echo error & whoami; } | sed 's/^/processed: /' Or more exactly { echo error & whoami 2>/dev/null; } | sed 's/^/processed: /'.
What if they are disjointed?
$ whoami > >(sed 's/^/processed: /') 2> >(echo error >&2)
error
processed: logan
This is the same as echo error >&2; whoami 2>/dev/null | sed 's/^/processed: /'.
Let's try with an invalid command.
$ BOB 2> >(cat) > >(echo hi >&2)
hi
BOB: command not found
This is the same as { echo hi >&2 & BOB >/dev/null; } 3>&1 1>&2 2>&3 | cat.
What if we want to introduce a custom file descriptor?
$ whoami > >(sed 's/^/processed: /') 3>&1 2> >(echo error >&3)
processed: error
processed: logan
This is the same as { echo error & whoami 2>/dev/null; } | sed 's/^/processed: /'. Here be careful that the order of redirections matter!
What if we mix valid and invalid commands in a substituted process?
$ > >(echo fine) 2> >(echo error >&2) 2> >(ls;whoami;echo bob >&2)
fine
error
Here we have preset stderr to print 'error' to terminal. So ls;whoami portion ends up printing 'fine' to terminal, and echo bob >&2 portion ends up printing 'error'.
Also consider
$> >(echo fine) 2> >(ls;whoami;BOB)
fine
BOB: command not found
Here the difference is that stderr still points to the terminal. So the BOB: command not found error message is just sent to the terminal unaltered.
Also consider
$ BOB > >(echo fine) 2> >(echo error >&2) 2> >(ls;whoami;echo bob >&2)
fine
error
This has the same effect as { ls & whoami & } | echo fine; { echo bob >&2 & BOB >/dev/null; } 3>&1 1>&2 2>&3 | echo error >&2. Here BOB is an invalid command.
Please note that the equivalences are for hints to aid understanding. They are not exact representations.