如何将 stdout 和 stderr 重定向到文件并将 stderr 显示到控制台?

如何将 stdout 和 stderr 重定向到文件并将 stderr 显示到控制台?

我知道如何重定向到文件,并使用 tee;在基本层面上。所以

$ alias outanderr='bash -c "echo stdout >&1; echo stderr >&2"'
# A fake "application" displaying both output and error messages.

$ outanderr 1>file      # redirect stdout to a file, display stderr
stderr

$ outanderr 2>file      # redirect stderr to a file, display stdout
stdout

$ outanderr 1>file 2>&1 # redirect both to a file, display nothing

$ outanderr | tee file; echo "-- file contents --" && cat file
# redirect stdout to a file, display both (note: order is messed up)
stderr
stdout
-- file contents --
stdout

$ outanderr 2>&1 | tee file; echo "-- file contents --" && cat file
# redirect both to a file, display both
stdout
stderr
-- file contents --
stdout
stderr

问题是:要写什么来代替问号才能得到以下输出:

$ outanderr ???; echo "-- file contents --" && cat file
# redirect both to a file, display stderr
stderr
-- file contents --
stdout
stderr

成分:

  • 假设bash。
  • 该订单应保存在文件中。
  • stderr 内容逐行实时显示,即无缓冲。
  • 可以使用单独的脚本文件。
  • 魔法可能是必要的。

答案1

2>&1 >>outputfile | tee --append outputfile

为了方便测试:

echo -n >outputfile; bash -c "echo stdout >&1; echo stderr >&2" 2>&1 >>outputfile |
  tee --append outputfile; echo "outputfile:"; cat outputfile

编辑1:

这是通过将 stdout (仅)写入文件,使 sterr stdout 以便它通过管道,然后让 tee 将其输出写入同一文件来实现的。

>>两次写入都必须在附加模式(而不是)下完成>,否则两者都会覆盖彼此的输出。

由于管道是一个缓冲区,因此不能保证输出以正确的顺序出现在文件中。如果应用程序连接到两个文件描述符(两个管道),这甚至不会改变。为了保证顺序,两个输出必须通过相同的通道并分别进行标记。或者你需要一些非常奇特的东西:

  1. 如果 stdout 和 stderr 都重定向到一个文件(不是同一个文件!)并且两个文件都位于 FUSE 卷上,则 FUSE 模块可以使用时间戳标记每个写入,以便第二个应用程序可以正确对数据进行排序并将其组合为真正的输出文件。或者您不标记数据,但让模块创建组合输出文件。很可能还没有 FUSE 模块可以做到这一点......
  2. stdout 和 stderr 都可以定向到/dev/null。应用程序的输出将通过 分离strace -f -s 32000 -e trace=write。在这种情况下,您必须反转转义。不用说,应用程序不会因为被跟踪而运行得更快。
  3. 也许通过使用现有的简单 FUSE 模块并跟踪模块而不是应用程序可以达到相同的效果。这可能比跟踪应用程序更快,因为(或者更确切地说:如果)模块的系统调用可能比应用程序少得多。
  4. 如果应用程序本身可以修改:应用程序可以在每次输出后停止(但我认为这只能从内部进行),并且仅在接收到 s 信号(SIGUSR1 或 SIGCONT)后继续。从管道读取的应用程序必须检查管道和文件中是否有新数据,并在每个新数据后发送信号。根据应用程序的类型,这可能比 strace 方法更快甚至更慢。 FUSE 将是最快速度的解决方案。

相关内容