tee stdout和stderr分离文件,同时将它们保留在各自的流中 [英] tee stdout and stderr to separate files while retaining them on their respective streams

查看:48
本文介绍了tee stdout和stderr分离文件,同时将它们保留在各自的流中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个脚本,该脚本本质上是充当(非交互式)命令创建的所有输出的通过日志,而不影响该命令对其他进程的输出.也就是说,stdout和stderr应该看起来像它们没有通过我的命令运行一样.

为此,我尝试将stdout和stderr分别重定向到两个不同的tee,每个tee用于一个不同的文件,然后重新组合它们,以便它们仍分别出现在stdout和stderr上.我还看到了许多其他有关发球和重定向的问题,并尝试了从中获得的一些答案,但是似乎都没有一个方法能够将流分离为单独的发球然后正确地重新组合在一起.

我的尝试已成功将输出拆分为正确的文件,但是没有为实际的stdout/stderr输出正确保留流.我在更复杂的设置中看到了这一点,因此我创建了简化的命令,在其中我将数据回显到stdout或stderr作为命令",如下所示.

以下是我尝试过的几件事:

  {命令|发球〜/tee.txt;} 2>& 1 |{tee〜/tee2.txt 1& 2;} 

运行我的简单测试,我看到:

  $ {{{echo"test" 1>& 2;} |发球〜/tee.txt;} 2>& 1 |{tee〜/tee2.txt 1& 2;}}>/dev/空测试$ {{{echo"test" 1& 2;} |发球〜/tee.txt;} 2>& 1 |{tee〜/tee2.txt 1& 2;}} 2>/dev/空$ 

好的,这是我所期望的.我正在回显stderr,因此,当我将最终的stderr重定向到/dev/null时,我希望什么都看不到,而当我仅重定向stdout时,我希望看到原始回显.

  $ {{{echo"test";} |发球〜/tee.txt;} 2>& 1 |{tee〜/tee2.txt 1& 2;}}>/dev/空测试$ {{{echo"test";} |发球〜/tee.txt;} 2>& 1 |{tee〜/tee2.txt 1& 2;}} 2>/dev/空$ 

这是倒退!我的命令仅将数据发送到stdout,因此当我将最终的stdout重定向为null时,我希望什么都看不到.但是反之亦然.

这是我尝试的第二个命令,它有点复杂:

  {命令2& 3 |发球〜/tee.txt;} 3& 1 1>& 2 |{tee/home/michael/tee2.txt 1>& 2;} 

不幸的是,我看到的行为与以前相同.

我真的看不到我在做什么错,但是似乎stdout正在以某种方式被破坏.在第一个命令的情况下,我怀疑这是因为我将stdout和stderr( 2>& 1 )组合到第二个T形管之前,但是如果是这种情况,我我希望在tee2.txt文件中同时看到stdout和stderr,但我没有看到-我只看到stderr!对于第二个命令,通过阅读我为该命令改编的答案给我的印象是,为了避免出现此问题,描述符已被交换,但是显然仍然存在问题.

我有另一个想法,也许第二条命令失败了,因为我正在重定向 1>& 2 ,并且这杀死了第一个发球区域的stdout.因此,我尝试使用 1>& 4 将其重定向,然后最后将其重定向回stdout:

  {命令2& 3 |发球〜/tee.txt;} 3& 1 1& 4 |{tee/home/michael/tee2.txt 1& 2 4>& 1;} 

但是现在我得到了:

  -bash:4:错误的文件描述符 

我还尝试将描述符2重定向回最后一个三通中的描述符1:

  {命令2& 3 |发球〜/tee.txt;} 3& 1 1>& 2 |{tee/home/michael/tee2.txt 1& 2 2>& 1;} 

和:

  {命令2& 3 |发球〜/tee.txt;} 3& 1 1>& 2 |{tee/home/michael/tee2.txt 1>& 2;} 2>& 1 

解决方案

基于过程替换的解决方案很简单,尽管没有您想象的那么简单.我的第一次尝试似乎应该有效

  {echo stdout;echo stderr& 2;}>>(tee〜/stdout.txt)\2>>(tee〜/stderr.txt) 

但是,它并没有按 bash 的预期工作,因为第二个 tee 从原始命令继承了其标准输出(因此它进入了 first tee ),而不是从调用Shell中获取.目前尚不清楚这是否应视为 bash 中的错误.

可以通过将输出重定向分为两个单独的命令来解决:

  {{echo stdout;echo stderr& 2;}>>(tee stdout.txt);} \2>>(tee stderr.txt) 

更新:第二个 tee 实际上应该是 tee stderr.txt& 2 ,以便将从标准错误中读取的内容打印回标准错误./p>

现在,标准错误的重定向发生在没有重定向其标准输出的命令中,因此它可以按预期的方式工作.外部复合命令的标准错误重定向到外部 tee ,其标准输出保留在终端上. inner 复合命令从外部继承其标准错误(因此也会传到外部 tee ,而标准输出重定向到内部的 tee .

I'm trying to write a script the essentially acts as a passthru log of all the output created by a (non-interactive) command, without affecting the output of the command to other processes. That is to say, stdout and stderr should appear the same as if they had not run through my command.

To do this, I'm trying to redirect stdout and stderr separately to two different tees, each for a different file, and then recombine them so that they still appear on stdout and stderr, respectively. I have seen a lot of other questions about teeing and redirecting and have tried some of the answers gleaned from those, but none of them seem to work combining both splitting the stream to separate tees and then recombining them correctly.

My attempts are successfully splitting the output into the right files, but the streams are not correctly retained for actual stdout/stderr output. I see this in a more complicated setting, so I created simplified commands where I echoed data to stdout or stderr as my "command" as shown below.

Here are a couple of things that I have tried:

{ command | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; }

Running my simple test I see:

$ { { { echo "test" 1>&2; } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } > /dev/null
test
$ { { { echo "test" 1>&2; } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } 2> /dev/null
$

Ok, this is as I expect. I am echoing to stderr, so I expect to see nothing when I redirect the final stderr to /dev/null and my original echo when I only redirect stdout.

$ { { { echo "test";  } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } > /dev/null
test
$ { { { echo "test";  } | tee ~/tee.txt; } 2>&1 | { tee ~/tee2.txt 1>&2; } } 2> /dev/null
$

This is backwards! My command sends only data to stdout, so I would expect to see nothing when I redirect the final stdout to null. But the reverse is true.

Here is the second command I tried, it is a bit more complicated:

{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&2 | { tee /home/michael/tee2.txt 1>&2; }

Unfortunately, I see the same identical behavior as before.

I can't really see what I am doing wrong, but it appears that stdout is getting clobbered somehow. In the case of the first command, I suspect that this is because I am combining stdout and stderr (2>&1) before I pipe it to the second tee, but if this were the case I would expect to see both stdout and stderr in the tee2.txt file, which I don't - I only see stderr! In the case of the second command, my impression from reading the answer I adapted for this command is that descriptors are getting swapped around so as to avoid this problem, but obviously something is still going wrong.

Edit: I had another thought, that maybe the second command is failing because I am redirecting 1>&2 and that is killing stdout from the first tee. So I tried to redirecting it with 1>&4 and then redirecting that back to stdout at the end:

{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&4 | { tee /home/michael/tee2.txt 1>&2 4>&1; }

But now I get:

-bash: 4: Bad file descriptor

I also tried redirecting descriptor 2 back to descriptor 1 in the final tee:

{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&2 | { tee /home/michael/tee2.txt 1>&2 2>&1; }

and:

{ command 2>&3 | tee ~/tee.txt; } 3>&1 1>&2 | { tee /home/michael/tee2.txt 1>&2; } 2>&1

解决方案

A process-substitution-based solution is simple, although not as simple as you might think. My first attempt seemed like it should work

{ echo stdout; echo stderr >&2; } > >( tee ~/stdout.txt ) \
                                 2> >( tee ~/stderr.txt )

However, it doesn't quite work as intended in bash because the second tee inherits its standard output from the original command (and hence it goes to the first tee) rather than from the calling shell. It's not clear if this should be considered a bug in bash.

It can be fixed by separating the output redirections into two separate commands:

{ { echo stdout; echo stderr >&2; } > >(tee stdout.txt ); } \
                                   2> >(tee stderr.txt )

Update: the second tee should actually be tee stderr.txt >&2 so that what was read from standard error is printed back onto standard error.

Now, the redirection of standard error occurs in a command which does not have its standard output redirected, so it works in the intended fashion. The outer compound command has its standard error redirected to the outer tee, with its standard output left on the terminal. The inner compound command inherits its standard error from the outer (and so it also goes to the outer tee, while its standard output is redirected to the inner tee.

这篇关于tee stdout和stderr分离文件,同时将它们保留在各自的流中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆