我如何使用 BASH 魔法来实现这一目标?
我只想在屏幕上看到 stderr 输出,
但我希望 stdout 和 stderr 都写入文件。
澄清:我希望 stdout 和 stderr 最终位于同一个文件中。按照它们发生的顺序。
不幸的是,下面的答案都没有做到这一点。
答案1
即使没有任何重定向,或者除了 之外什么都没有>logfile 2>&1
,您也不能保证按生成顺序看到输出。
对于初学者来说,应用程序的 stdout 将是行缓冲的(到 tty)或缓冲的(到管道),但 stderr 是无缓冲的,因此就读者而言,输出顺序之间的关系被破坏。您可以构建的任何管道中的后续阶段都不会获得对两个流的确定性有序访问(它们从概念上讲是并行发生的事情,并且您始终受调度程序的约束 - 如果当您的读者获得切片时,作者已经写入两个管道,您无法分辨哪个先出现)。
“它们发生的顺序”只有应用程序才真正知道。 stdout/stderr 之间的输出排序是一个众所周知的(也许是经典的)问题。
答案2
当您使用该结构时:1>stdout.log 2>&1
两者标准错误和标准输出被重定向到该文件,因为标准输出重定向是在之前设置的标准错误重定向。
如果你颠倒顺序你可以得到标准输出重定向到一个文件并且然后复制标准错误到标准输出这样你就可以将它通过管道传输到tee
.
$ cat test
#!/bin/sh
echo OUT! >&1
echo ERR! >&2
$ ./test 2>&1 1>stdout.log | tee stderr.log
ERR!
$ cat stdout.log
OUT!
$ cat stderr.log
ERR!
答案3
我已经能够通过将以下行放在 bash 脚本的顶部来实现此目的:
exec 1>>log 2> >(tee -a log >&2)
这会将 stdout 重定向到文件log
( 1>>log
),然后将 stderr 重定向到文件log
( 2> >(tee -a log
) 并将其定向回 stderr ( >&2)
。这样,我得到一个文件 ,log
它按顺序显示 stdout 和 stderr,并且 stderr 也是像往常一样显示在屏幕上。
问题是它似乎只在我附加到文件时才起作用。如果我不附加,则两个重定向似乎会互相破坏,并且我只能得到最后一个输出。
答案4
我一直在努力满足这个确切的要求,最终找不到一个简单的解决方案。我最终做的是这样的:
TMPFILE=/tmp/$$.log
myCommand > $TMPFILE 2>&1
[ $? != 0 ] && cat $TMPFILE
date >> myCommand.log
cat $TMPFILE >> myCommand.log
rm -f $TMPFILE
它将 stdout 和 stderr 以正确的交错顺序附加到日志文件中。如果发生任何错误(由命令的退出状态确定),它会发送整个输出(stdout和stderr) 到 stdout,同样以正确的交错顺序。我发现这是满足我的需求的合理妥协。如果您想要单次运行日志文件而不是不断增长的多运行日志文件,则更简单:
myCommand > myCommand.log 2>&1
[ $? != 0 ] && cat myCommand.log