将两个并发程序的输出与bash结合起来

时间:2012-01-31 13:01:15

标签: bash shell unix

我希望将两个并发程序(日志文件中的尾部)的输出捕获到bash中的一个输出流中。

我使用这个示例程序进行测试:

function foo { for i in $(seq 1 10); do echo "program $*"; sleep 1; done }

现在以下工作正常

(foo bar & foo baz &) | tee /tmp/output

但是一旦我在混合中添加额外的管道就不再有效了:

(foo bar | grep bar & foo baz &) | tee /tmp/output # does't work

输出变为顺序。我可以制作一个包含grep的单独程序,但我想知道是否有办法解决这个问题。

如果有人能解释为什么它不起作用,我会非常高兴。

2 个答案:

答案 0 :(得分:7)

好问题!这个让我感到难过,但我想我知道发生了什么。发生的事情是grep正在缓冲输出。所以,如果你让它运行,你会看到它最终泛滥。如果你碰巧使用GNU grep,请尝试传递--line-buffered选项:

(foo bar | grep --line-buffered bar & foo baz &) | tee /tmp/output

为了冒险猜测,并且提醒你基本上是这样,我会说grep正在缓冲更多输出,因为isatty(1)表示它不是写到TTY(即使您正在通过tee观看TTY上的输出)。通过缓冲更多输出,可以减少write()次呼叫,并且效率更高。运行grep并观察终端输出的常见行为是行缓冲 - 在找到行时会出现这些行。此选项强制grep以该模式运行。

请注意,正如手册页警告的那样,这可能会对grep产生性能影响。

答案 1 :(得分:1)

由于在foo bargrep之间使用了管道,你正在使grep等待foo bar命令的输出,这就是为什么所有带有bar的行都来了在巴兹线之后立刻。如果你真的想从命令中grep一些东西,那么定义另一个函数如下:

function foo1 { for i in {1..3}; do echo "program $*" | grep "$*"; sleep 1; done }

然后执行:

(foo1 bar & foo baz &) | tee /tmp/output

现在你会注意到输出如下:

program baz
program bar
program baz
program bar
program baz
program bar
...
...