【问题标题】:Combine output of two concurrent programs with bash将两个并发程序的输出与 bash 结合起来
【发布时间】:2012-01-31 13:01:14
【问题描述】:

我想将两个并发程序的输出(日志文件的尾部)捕获到 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 的单独程序,但我想知道是否有办法解决这个问题。

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

【问题讨论】:

    标签: bash shell unix


    【解决方案1】:

    好问题!这让我有点难过,但我想我知道发生了什么。发生的事情是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 产生性能影响。

    【讨论】:

    • "即使是这样,因为 tee"。 grep 写入 tty。 grep 正在写入管道,而 tee 正在写入 tty。
    • 你说得对。我的措辞很糟糕——我会编辑我的帖子来澄清一下。
    【解决方案2】:

    由于在foo bargrep 之间使用了管道,您正在使用grep 等待foo bar 命令的输出,这就是为什么所有带有bar 的行都在baz 行之后立即出现。如果您真的想从命令中获取某些内容,请定义另一个函数,如下所示:

    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
    ...
    ...
    

    【讨论】:

      猜你喜欢
      • 2021-09-28
      • 2020-07-07
      • 2020-02-03
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 2019-09-03
      • 2011-08-02
      • 2021-11-23
      相关资源
      最近更新 更多