18

重定向 stdout+stderr 以使两者都写入文件同时仍输出到 stdout 很简单:

cmd 2>&1 | tee output_file

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

some_magic_tee_variant combined_output cmd > >(command-expecting-stdout) 2> >(command-expecting-stderr)

因此,combined_output 包含保留顺序的两者,但 command-expecting-stdout 仅获取 stdout,而 command-expecting-stderr 仅获取 stderr。基本上,我想记录标准输出+标准错误,同时仍然允许标准输出和标准错误被单独重定向和管道。tee 方法的问题在于它将它们聚集在一起。有没有办法在 bash/zsh 中做到这一点?

4

5 回答 5

2

From what I unterstand this is what you are looking for. First I made a litte script to write on stdout and stderr. It looks like this:

$ cat foo.sh 
#!/bin/bash

echo foo 1>&2
echo bar

Then I ran it like this:

$ ./foo.sh 2> >(tee stderr | tee -a combined) 1> >(tee stdout | tee -a combined)
foo
bar

The results in my bash look like this:

$ cat stderr
foo
$ cat stdout 
bar
$ cat combined 
foo
bar

Note that the -a flag is required so the tees don't overwrite the other tee's content.

于 2012-09-20T17:30:22.127 回答
1

Victor Sergienko 的评论对我有用,将 exec 添加到它的前面使整个脚本都可以使用(而不必将其放在单个命令之后)

exec 2> >(tee -a output_file >&2) 1> >(tee -a output_file)

于 2015-04-07T21:37:31.977 回答
1

这是我的做法:

exec 3>log ; example_command 2>&1 1>&3 | tee -a log ; exec 3>&-

工作示例

bash$ exec 3>log ; { echo stdout ; echo stderr >&2 ; } 2>&1 1>&3 | \
      tee -a log ; exec 3>&-
stderr
bash$ cat log
stdout
stderr

这是它的工作原理:

exec 3>log设置文件描述符 3 以重定向到名为 log 的文件,直至另行通知。

example_command为了使它成为一个工作示例,我使用了{ echo stdout ; echo stderr >&2 ; }. 或者您可以使用ls /tmp doesnotexist来提供输出。

此时需要跳转到管道|,因为 bash 首先执行此操作。管道设置一个管道并将文件描述符 1 重定向到该管道。所以现在,STDOUT 正在进入管道。

现在我们可以回到我们从左到右的解释中的下一个位置:2>&1这表示程序中的错误将转到 STDOUT 当前指向的位置,即进入我们刚刚设置的管道。

1>&3表示 STDOUT 被重定向到文件描述符 3,我们之前设置它输出到log文件。所以命令中的 STDOUT 只是进入日志文件,而不是终端的 STDOUT。

tee -a log从管道获取它的输入(你会记住现在是命令中的错误),并将其输出到 STDOUT并将其附加到log文件中。

exec 3>&-关闭文件描述符 3.

于 2014-04-15T10:57:51.873 回答
1
{ { cmd | tee out >&3; } 2>&1 | tee err >&2; } 3>&1

或者,学究起来:

{ { cmd 3>&- | tee out >&3 2> /dev/null; } 2>&1 | tee err >&2 3>&- 2> /dev/null; } 3>&1

请注意,试图保持秩序是徒劳的。这基本上是不可能的。唯一的解决方案是修改“cmd”或使用一些LD_PRELOADgdb破解,

于 2012-10-14T20:52:02.843 回答
1

秩序确实可以保留。这是一个示例,它按照生成的顺序将标准输出和错误捕获到日志文件中,同时在您喜欢的任何终端屏幕上仅显示标准错误。调整以满足您的需求。

1.打开两个窗口(shell)

2.创建一些测试文件

touch /tmp/foo /tmp/foo1 /tmp/foo2

3.在窗口1中:

mkfifo /tmp/fifo
</tmp/fifo cat - >/tmp/logfile

4.然后,在window2中:

(ls -l /tmp/foo /tmp/nofile /tmp/foo1 /tmp/nofile /tmp/nofile; echo successful test; ls /tmp/nofile1111) 2>&1 1>/tmp/fifo | tee /tmp/fifo 1>/dev/pts/1

/dev/pts/1 可以是您想要的任何终端显示。子shell依次运行一些“ls”和“echo”命令,一些成功(提供stdout)和一些失败(提供stderr),以便生成混合的输出和错误消息流,以便您可以验证正确的顺序日志文件。

于 2013-08-02T20:10:54.957 回答