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