像accepted answer well explained by lhunath一样可以使用
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
请注意,如果您使用 bash,可能会遇到一些问题。
让我以matthew-wilcoxson 为例。
对于那些“眼见为实”的人来说,快速测试一下:
(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
就我个人而言,当我尝试时,我得到了这样的结果:
user@computer:~$ (echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
user@computer:~$ Test Out
Test Err
两条消息没有出现在同一级别。为什么Test Out 好像是我之前的命令?
提示在一个空白行,让我认为过程没有完成,当我按Enter这个修复它。
当我检查文件的内容时,没关系,重定向有效。
让我们再做一次测试。
function outerr() {
echo "out" # stdout
echo >&2 "err" # stderr
}
user@computer:~$ outerr
out
err
user@computer:~$ outerr >/dev/null
err
user@computer:~$ outerr 2>/dev/null
out
再次尝试重定向,但使用此功能。
function test_redirect() {
fout="stdout.log"
ferr="stderr.log"
echo "$ outerr"
(outerr) > >(tee "$fout") 2> >(tee "$ferr" >&2)
echo "# $fout content :"
cat "$fout"
echo "# $ferr content :"
cat "$ferr"
}
就我个人而言,我有这样的结果:
user@computer:~$ test_redirect
$ outerr
# stdout.log content :
out
out
err
# stderr.log content :
err
user@computer:~$
空行没有提示,但是看不到正常输出,stdout.log内容好像有错,只有stderr.log好像没问题。
如果我重新启动它,输出可能会有所不同...
那么,为什么?
因为,like explained here:
请注意,在 bash 中,此命令会在 [first command] 完成后立即返回,即使 tee 命令仍在执行(ksh 和 zsh 确实会等待子进程)
所以,如果你使用 bash,最好使用this other answer 中给出的更好的例子:
{ { outerr | tee "$fout"; } 2>&1 1>&3 | tee "$ferr"; } 3>&1 1>&2
它将解决以前的问题。
现在的问题是,如何检索退出状态码?
$? 不起作用。
我没有找到比使用set -o pipefail(set +o pipefail 关闭)打开管道故障并像这样使用${PIPESTATUS[0]} 更好的解决方案
function outerr() {
echo "out"
echo >&2 "err"
return 11
}
function test_outerr() {
local - # To preserve set option
! [[ -o pipefail ]] && set -o pipefail; # Or use second part directly
local fout="stdout.log"
local ferr="stderr.log"
echo "$ outerr"
{ { outerr | tee "$fout"; } 2>&1 1>&3 | tee "$ferr"; } 3>&1 1>&2
# First save the status or it will be lost
local status="${PIPESTATUS[0]}" # Save first, the second is 0, perhaps tee status code.
echo "==="
echo "# $fout content :"
echo "<==="
cat "$fout"
echo "===>"
echo "# $ferr content :"
echo "<==="
cat "$ferr"
echo "===>"
if (( status > 0 )); then
echo "Fail $status > 0"
return "$status" # or whatever
fi
}
user@computer:~$ test_outerr
$ outerr
err
out
===
# stdout.log content :
<===
out
===>
# stderr.log content :
<===
err
===>
Fail 11 > 0