Skip to main content

Command Palette

Search for a command to run...

Redirecting process substitutions

Updated
3 min readView as Markdown

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.

More from this blog

Linux and Web

31 posts