pipe stdout and stderr to two different processes in shell script?
Use another file descriptor
{ command1 2>&3 | command2; } 3>&1 1>&2 | command3
You can use up to 7 other file descriptors: from 3 to 9.
If you want more explanation, please ask, I can explain ;-)
Test
{ { echo a; echo >&2 b; } 2>&3 | sed >&2 's/$/1/'; } 3>&1 1>&2 | sed 's/$/2/'
output:
b2
a1
Example
Produce two log files:
1. stderr
only
2. stderr
and stdout
{ { { command 2>&1 1>&3; } | tee err-only.log; } 3>&1; } > err-and-stdout.log
If command
is echo "stdout"; echo "stderr" >&2
then we can test it like that:
$ { { { echo out>&3;echo err>&1;}| tee err-only.log;} 3>&1;} > err-and-stdout.log
$ head err-only.log err-and-stdout.log
==> err-only.log <==
err
==> err-and-stdout.log <==
out
err
Using process substitution:
command1 > >(command2) 2> >(command3)
See http://tldp.org/LDP/abs/html/process-sub.html for more info.
The accepted answer results in the reversing of stdout
and stderr
. Here's a method that preserves them (since Googling on that purpose brings up this post):
{ command 2>&1 1>&3 3>&- | stderr_command; } 3>&1 1>&2 | stdout_command
Notice:
3>&-
is required to prevent fd 3 from being inherited bycommand
. (As this can lead to unexpected results depending on whatcommand
does inside.)
Parts explained:
Outer part first:
3>&1
-- fd 3 for{ ... }
is set to what fd 1 was (i.e.stdout
)1>&2
-- fd 1 for{ ... }
is set to what fd 2 was (i.e.stderr
)| stdout_command
-- fd 1 (wasstdout
) is piped throughstdout_command
Inner part inherits file descriptors from the outer part:
2>&1
-- fd 2 forcommand
is set to what fd 1 was (i.e.stderr
as per outer part)1>&3
-- fd 1 forcommand
is set to what fd 3 was (i.e.stdout
as per outer part)3>&-
-- fd 3 forcommand
is set to nothing (i.e. closed)| stderr_command
-- fd 1 (wasstderr
) is piped throughstderr_command
Example:
foo() {
echo a
echo b >&2
echo c
echo d >&2
}
{ foo 2>&1 1>&3 3>&- | sed -u 's/^/err: /'; } 3>&1 1>&2 | sed -u 's/^/out: /'
Output:
out: a
err: b
err: d
out: c
(Order of a -> c
and b -> d
will always be indeterminate because there's no form of synchronization between stderr_command
and stdout_command
.)