I'm trying to understand what causes the difference in these 2 constructs that I thought were functionally equivalent:
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | sed 's/^/stdout: /'
stdout: stderr: foo
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
stderr: foo
EDIT: If I understood user1133275 right, he suggests that >(sed 's/^/stdout: /')
is not run unless the subshell ( echo foo >&2 )
outputs to stdout. However, that would mean that the following:
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(echo baz)
baz
stderr: foo
should not display baz
.
EDIT 2: Perhaps also of interest, sed doesn't output stdout:
on empty input, even when piped:
$ sed 's/^/stdout: /' < /dev/null
$ printf "" | sed 's/^/stdout: /'
$
Best Answer
Your first command,
in simplified form (using a temporary file to hold the data produced by
echo
):I.e., the first
sed
reads what is produced on standard error from theecho
and writes to standard output and the secondsed
reads and modifies that.Your second command,
in simplified form,
Here, the
sed
that gets the standard error output produces output while the othersed
that gets the standard output output (which is nothing) does not produce any output (since it didn't get any input and since it did not insert or append any data).Another way of formulating it:
First command:
Second command:
In short, the second
sed
in the second command never reads anything. In particular, it does not read the output from the firstsed
as in the first command.Using extremely simplified symbols, the first command is something like
where
something1
writes to standard output, which is read bysomething2
.The second command, using the same notation,
i.e.
something1
andsomething2
is not even connected to each other, andsomething2
can not in any way read whatsomething1
is producing. Furthermore, sinceutility-writing-to-stderr
does not produce anything on its standard output stream,something2
will have nothing to read from its standard input.