将标准输出和标准错误重定向到一个文件,只将标准错误的副本复制到另一个文件。

4
我想将标准输出和标准错误输出重定向到同一个文件:
./foo.sh >stdout_and_stderr.txt 2>&1

同时将stderr重定向到另一个文件。我尝试了这样的变化:

./foo.sh >stdout_and_stderr.txt 2>stderr.txt 2>&1

但是在bash中,它们都不能完全正常工作,例如,stderr只被重定向到一个输出文件中。重要的是,合并文件要保留第一个代码段的行顺序,因此不能将其转储到不同的文件中,然后再进行合并。

在bash中是否有一个简洁的解决方案?


2
我认为您不可能通过单个进程来完成这项任务,而且肯定不能像问题中展示的那样简单地扭曲重定向。您可以尝试将某些内容导入tee进行管道处理,但由于缓冲等原因,生成的交错结果很可能与终端屏幕上看到的不同。 - Jonathan Leffler
请注意,您的第一个命令(./foo.sh 2>&1 >file)将错误发送到原始标准输出,并将标准输出(但不是重定向的标准错误)发送到文件中。如果您想要在file中同时包含两者,则必须使用./foo.sh >file 2>&1,反转重定向的顺序。它们从左到右进行解释。 - Jonathan Leffler
非常好的观点,只是修复了2>&1的顺序,感谢@JonathanLeffler。 - CyGuy
3个回答

3
您可以使用额外的文件描述符和tee
{ foo.sh 2>&1 1>&3- | tee stderr.txt; } > stdout_and_stderr.txt 3>&1

请注意,行缓冲可能导致标准输出的顺序出现问题。如果这是一个问题,有一些方法可以克服这个问题,包括使用unbuffer


这看起来像是一个简单的一行代码,但我无法让它工作。我得到了“bash:syntax error near unexpected token `}'”错误。删除分号后错误消失了,但当我尝试cat文件时,我得到了“bash:3:Bad file descriptor”的错误。 - CyGuy
1
@CyGuy:如果你没有包含开头的花括号或者在它后面省略了空格,你就会得到那个错误。 - Dennis Williamson
当遵守空格时,Indeed 能够正常工作 @DennisWilliamson - CyGuy
@DennisWilliamson,我不明白POSIX语义如何允许unbuffer或任何其他工具确定stderr和stdout之间的写入顺序,当它们不是完全相同的文件描述符的副本时。如果涉及到FIFO,则在写入FIFO并安排程序从中读取(然后,在tee的情况下,执行另一个写入已读取内容的操作)之间涉及的延迟量是不确定的,无论链的前面有多么立即的刷新。 - Charles Duffy

1
使用进程替换,您可以得到一个适度的近似,以满足您的需求:
file1=stdout.stderr
file2=stderr.only
: > $file1    # Zap the file before starting
./foo.sh >> $file1 2> >(tee $file2 >> $file1)

这里给文件命名是因为其中一个名称被重复使用了。标准输出被写入到$file1中。标准错误被写入到管道中,该管道运行tee并将输入的一份副本(即标准错误输出)写入$file2,同时也将第二份副本写入$file1>> 重定向意味着文件以O_APPEND模式打开,因此每次写入都将在末尾完成,而不管其他进程也写入了什么。

如评论所述,与在终端上简单运行./foo.sh相比,输出通常会以不同的方式交错。多个缓冲区正在进行多个设置以确保发生这种情况。由于行在缓冲区大小边界上断开的方式,您可能还会得到部分行。


0

这条来自@jonathan-leffler的评论应该作为答案:

请注意,您的第一个命令(./foo.sh 2>&1 >file)将错误发送到原始标准输出,并将标准输出(但不是重定向的标准错误)发送到文件中。

如果您想要两者都在文件中,您需要使用./foo.sh >file 2>&1,颠倒重定向的顺序。

它们从左到右进行解释。


1
我的关于问题中重定向的评论是有效的,但并没有解决问题。问题在于如何使一个写函数调用同时写入两个不同的文件,而简短的回答是“你不能”。因此,标准错误必须写入可以产生两个副本的地方。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接