【问题标题】:In a shell script, how to redirect stdout to console and both stdout and stderr to a file?在 shell 脚本中,如何将 stdout 重定向到控制台,并将 stdout 和 stderr 重定向到文件?
【发布时间】:2021-09-08 14:09:30
【问题描述】:

我需要将 stdout 重定向到控制台,并将 stdout 和 stderr 重定向到文件。这需要在 shell 脚本中完成。 我发现下面的代码可以同时重定向到控制台和日志文件,现在我需要将 stderr 删除到控制台。

exec > >(tee -i "output.log") 2>&1

你能帮帮我吗?

【问题讨论】:

  • 作为一个额外的复杂因素,请记住 stdout 通常是缓冲的,而 stderr 通常不是。将两者都重定向到一个公共日志可能会导致它们被写出实际的时间顺序。解决这个问题的一种方法是取消缓冲两者,例如将两者都路由到 stderr,但这会使您的解决方案更加复杂。为什么您不希望 stderr 也进入控制台?这对我来说似乎违反直觉。
  • 是的,我就是这么想的。尤其是多线程,它可能会在其他任务完成之前发现错误并开始生成报告。

标签: bash sh stdout stderr tee


【解决方案1】:

源自此答案: How do I get both STDOUT and STDERR to go to the terminal and a log file?

我测试了以下代码:

echo '' > out.log
exec 1> >(tee -a -i out.log) 2> >(tee -a -i out.log > /dev/null)
>&2 echo yay
echo nay

STDERR 内容进入文件而不是控制台,而 STDOUT 进入两者。

【讨论】:

  • exec 2>output.log > >(tee /dev/tty >&2) 不会做同样的事情吗?
  • 看起来是的
  • 为什么需要两个 T 恤?他试图摆脱 STDERR 到控制台,所以它只去日志。
【解决方案2】:

我认为你应该这样启动它:

your-command 2>&1 | tee -i "output.log"

它将 stdin 和 stderr 都通过管道传输到 tee -i output.log,这将在写入之前回显文本。

或者,忽略标准错误(到 /dev/null 的管道):

your-command 2>/dev/null | tee -i "output.log"

或者你的命令修改为 /dev/null 重定向:

exec > >(tee -i "output.log") 2>/dev/null

【讨论】:

  • 这些都不符合 OP 的要求。
【解决方案3】:

应该是something like this,但你不必开第二个。

exec 1> >( tee stdout.txt ) 2> stderr.txt

输出 1 是 tee'd,因此您可以在屏幕上和 stdout.txt 中看到它
错误2 直接进入stderr.txt

【讨论】:

  • 我相信你可以使用相同的文本名称,如果你希望它们都被重定向到那里,但我不知道两个流在崩溃期间如何解决。消息可能重叠。欢迎您尝试,但对我来说这听起来像是捉鬼敢死队,“不要越过溪流。”