With zsh
(and zsh
only) and its multios
feature:
your-cmd 2> stdout+stderr.log >&2 2> stderr.log
As fd 2 is redirected twice, zsh
implements an internal tee
to have it sent to both files.
With bash
(or any Bourne-like shell (other than zsh
where you'd need to disable multios
for it to work here)), you can do the tee
ing by hand with:
{ your-cmd 2>&1 >&3 3>&- | tee stderr.log 3>&-; } > stderr+stdout.log 3>&1
(though you lose the exit status of your-cmd
. zsh
has it in $pipestatus[1]
, bash
in "${PIPESTATUS[0]}"
though (provided the redirection into stderr+stdout.log
didn't fail)).
To record the pid of your-cmd
, you could do:
{ sh -ec 'echo "$$" > /var/run/pidfile; exec your-cmd' 2>&1 >&3 3>&- |
tee stderr.log 3>&-; } > stderr+stdout.log 3>&1
With yash
and it's process redirection feature:
your-cmd > stdout+stderr.log 2>(tee stderr.log)
(but note that yash
will not wait for the termination of that tee
command, so the log files may not be complete by the time you run the next command after that).
Something similar (and with the same caveat) can be done with process substitution in bash
, zsh
and ksh93
:
{ your-cmd 2> >(tee stderr.log); } > stderr+stdout.log
To run in background and get the pid:
(exec your-cmd 2> >(tee stderr.log)) > stderr+stdout.log & pid=$!
With rc
:
{your-cmd |[2=0] tee stderr.log} > stdout+stderr.log
rc
's pipes allow specifying which file descriptors are connected to the pipe. With other shells, it's always fd 1 of the left command and fd 0 of the right one (hence the little dance with fd 3 above to shift file descriptors around). rc
will report failure if either your-cmd
or tee
fails, though the exact number may be lost.