如何将stdout + stderr重定向到一个文件,同时保持流分离?

Jos*_*vin 14 unix bash shell zsh tee

重定向stdout + stderr,以便在仍然输出到stdout时写入文件都很简单:

cmd 2>&1 | tee output_file
Run Code Online (Sandbox Code Playgroud)

但是现在来自cmd的stdout/stderr都来了stdout.我想将stdout + stderr写入同一个文件(因此,假设cmd是单线程的,则保留排序)但是仍然可以单独重定向它们,如下所示:

some_magic_tee_variant combined_output cmd > >(command-expecting-stdout) 2> >(command-expecting-stderr)
Run Code Online (Sandbox Code Playgroud)

因此,combined_output包含保留顺序的两者,但命令期望-stdout仅获取stdout,而命令期望-stderr仅获取stderr.基本上,我想记录stdout + stderr,同时仍然允许stdout和stderr分别重定向和管道.发球方法的问题在于它们将它们融合在一起.有没有办法在bash/zsh中执行此操作?

kek*_*eks 2

据我了解,这就是您正在寻找的。首先,我制作了一个小脚本来编写标准输出和标准错误。它看起来像这样:

$ cat foo.sh 
#!/bin/bash

echo foo 1>&2
echo bar
Run Code Online (Sandbox Code Playgroud)

然后我像这样运行它:

$ ./foo.sh 2> >(tee stderr | tee -a combined) 1> >(tee stdout | tee -a combined)
foo
bar
Run Code Online (Sandbox Code Playgroud)

我的结果bash如下所示:

$ cat stderr
foo
$ cat stdout 
bar
$ cat combined 
foo
bar
Run Code Online (Sandbox Code Playgroud)

请注意, -a 标志是必需的,因此tees 不会覆盖另一个tee的内容。

  • 这不会保留顺序;如果您更改“foo.sh”以将“echo”语句包装在循环中,您会发现“combined”*不会*最终以“foo”和“bar”严格交替结束。 (2认同)