【发布时间】:2018-09-05 23:59:28
【问题描述】:
我在stdout 和stderr 中有大量文本;我想将所有内容记录在一个文件中(以相同的顺序),并在控制台中仅打印来自stdout 的内容以供进一步处理(如grep)。
> file 或 &> file 的任何组合,即使与 | 或 |& 将永久重定向流,之后我无法管道它:
my_command > output.log | grep something # logs only stdout, prints only stderr
my_command &> output.log | grep something # logs everything in correct order, prints nothing
my_command > output.log |& grep something # logs everything in correct order, prints nothing
my_command &> output.log |& grep something # logs everything in correct order, prints nothing
tee 的任何使用都会
- 打印来自
stderr的内容然后记录来自stdout的所有内容并打印出来,这样我就失去了输入文本的顺序 - 如果我使用
|& tee,则以正确的顺序记录两者,但我无法控制流,因为现在所有内容都在stdout中。
示例:
my_command | tee output.log | grep something # logs only stdout, prints all of stderr then all of stdout
my_command |& tee output.log | grep something # logs everything, prints everything to stdout
my_command | tee output.log 3>&1 1>&2 2>&3 | tee -a output.log | grep something # logs only stdout, prints all of stderr then all of stdout
现在我完全没有想法了。
这是我的测试用例的样子:
testFunction() {
echo "output";
1>&2 echo "error";
echo "output-2";
1>&2 echo "error-2";
echo "output-3";
1>&2 echo "error-3";
}
我希望我的控制台输出看起来像:
output
output-2
output-3
我的 output.log 文件看起来像:
output
error
output-2
error-2
output-3
error-3
有关更多详细信息,我正在使用 grep 过滤 mvn clean install 的输出,以仅在终端中保留最少的信息,但我也希望在某处拥有完整的日志,以防我需要调查堆栈跟踪或者其他的东西。 java 测试日志被发送到stderr,所以我选择在控制台输出中丢弃它。
【问题讨论】:
-
操作系统级缓冲意味着实际上没有办法在不同的文件句柄上建立特定的顺序。也许运行一个包装器,它在一个紧密的循环中读取两个无缓冲的流。
-
可以重建原始顺序,但您需要类似
sysdig(在执行前将系统调用转储到环形缓冲区)来保证正确性。 -
(我什至不会将其描述为“操作系统级缓冲”,这就是问题所在——即使您根本没有缓冲,
tee也需要时间来执行直接写入文件没有,让一个 FD 写入 FIFO 到tee和另一个直接写入文件不同步;同样,程序的调度可以随意延迟,因此不能保证两次写入 FIFO 连接到tee的不同副本将导致这些副本被安排以与原始写入发生的顺序相同的顺序运行)。 -
related question 指定重新组合
stdout和stderr,但我的问题更多是关于过滤它们。是否没有tee-equivalent 但它从两个流中读取并写入两个流?然后我可以简单地过滤它。 -
分割成两个流的事实意味着不再有操作系统级别的接口(无需进入 MacOS/BSD 上的
ptrace、sysdig、dtrace等)让您精确确定对两个不同流的一对写入的顺序。无论您是在过滤还是合并,都不是重点——重点是,如果您想区别对待流,但要保留写入之间的顺序对于他们,您需要使用类似于链接问题答案中给出的方法。
标签: bash maven io-redirection