Home > Software design >  Bash Send stdout to one process and stderr to another process
Bash Send stdout to one process and stderr to another process

Time:05-18

I have a question on process substitution and bash redirection.

Consider

$ zzz > >(echo fine) 2> >(echo error)

I expected output fine error since zzz is not a valid command but instead I just get fine. Why is this?

This works as expected

$ zzz 2> >(echo error)
error

If I swap the order

$ zzz 2> >(echo error) >(echo fine)
fine
error

Tried

$ 3> >(echo nested) zzz 2> >(yyy 2>&3)
nested

CodePudding user response:

It's because bash applies the output redirection (the > >(echo fine) part) to the echo error process as well as to the zzz command itself. Since echo fine doesn't do anything with that input, the "error" text just vanishes. You can see this by replacing echo fine with something that actually displays what it got as input:

$ zzz > >(sed 's/^/processed through sed: /') 2> >(echo error)
$ processed through sed: error

Note that (at least when I tried it), this looks weird because the shell printed its next prompt ("$ ") before sed got around to outputting the modified error message. The subprocesses created by >( ) are effectively backgrounded, so the shell doesn't wait for them to finish.

If you want to avoid this (or at least work around it), you can copy the stdout file descriptor to a different FD, then redirect output from the other process to that alternate FD. Here's an example using FD #3:

$ zzz 3>&1 > >(echo fine) 2> >(echo error >&3)
fine
error

BTW, if you put the redirects in the other order, the redirect to echo fine happens logically after the echo error process is started, so echo fine's output goes to the terminal as normal. On the other hand, if you do it that way, then errors from the echo fine command would be redirected to echo error.

$ zzz 2> >(echo error) > >(echo fine; yyy)
error
fine

(In this example, the "command not found" errors for both xxx and yyy are sent to echo error, which ignores them.)

BTW^2, zsh also implements process substitution, but doesn't apply inherited redirects this way:

zsh% zzz > >(echo fine) 2> >(echo error)
fine
error

As far as I know, process substitution isn't defined by any standard, so I don't think there's a way to define which shell's implementation is "more correct".

CodePudding user response:

As I said in the above

$ zzz > >(echo run) 2> >(echo zzz)
run

zzz is not outputted.

But we can circumvent this by

$ 3> >(echo zzz) zzz > >(echo run) 2>&3
zzz
run
  • Related