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

TWi*_*Rob 19 bash io-redirection files

我知道如何重定向到一个文件,并使用 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
Run Code Online (Sandbox Code Playgroud)

问题是:写什么来代替问号以获得以下输出:

$ outanderr ???; echo "-- file contents --" && cat file
# redirect both to a file, display stderr
stderr
-- file contents --
stdout
stderr
Run Code Online (Sandbox Code Playgroud)

内容:

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

Hau*_*ing 13

2>&1 >>outputfile | tee --append outputfile
Run Code Online (Sandbox Code Playgroud)

为方便测试:

echo -n >outputfile; bash -c "echo stdout >&1; echo stderr >&2" 2>&1 >>outputfile |
  tee --append outputfile; echo "outputfile:"; cat outputfile
Run Code Online (Sandbox Code Playgroud)

编辑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 将是最大速度的解决方案。

  • 注意这有一个竞争条件,引入了交换/错误行的可能性,但我认为这是无法避免的。 (2认同)