如何从多个进程中拆分和重新加入STDOUT?

时间:2014-04-23 21:46:59

标签: bash stdout stdin pipe tee

我正在开发一个有一些分支点然后合并的管道 - 它们看起来像这样:

         command2
        /        \
command1          command4
        \        /
         command3

每个命令写入STDOUT并通过STDIN接受输入。需要将来自command1的STDOUT传递给 命令2和命令3,它们按顺序运行,并且它们的输出需要有效连接并传递给command4。我最初认为这样的事情会起作用:

$ command1 | (command2; command3) | command4

但这并不起作用,因为只有来自command2的STDOUT传递给命令4,当我删除command4时,很明显command3没有从command1传递适当的流 - 换句话说,就好像command2正在耗尽或消耗流。我用{command2;得到了相同的结果command3;在中间也是如此。所以我想我应该使用'tee' with process substitution,并尝试了这个:

$ command1 | tee >(command2) | command3 | command4

但令人惊讶的是,它也没有工作 - 看来command1 的输出和命令2的输出被传送到command3,导致错误,只有command3的输出用管道输入4。我确实发现以下内容从command2和command3获取适当的输入和输出:

$ command1 | tee >(command2) >(command3) | command4

但是,这会将command1的输出流式传输到command4,这会导致问题,因为command2和command3产生的命令与command1不同。我到达的解决方案似乎很苛刻,但确实有效:

$ command1 | tee >(command2) >(command3) > /dev/null | command4

这会抑制command1将其输出传递给command4,同时从command2和command3收集STDOUT。它有效,但我觉得我错过了一个更明显的解决方案。我呢?我已经阅读了几十个主题并且没有找到解决这个问题的解决方案,这个解决方案在我的用例中有效,我也没有看到关于拆分和重新加入流的确切问题的详细说明(尽管我可以&# 39;是第一个处理这个问题的人。我应该只使用命名管道吗?我试过但很难让它工作得那么好,所以也许这是另一个故事的另一个故事。我在RHEL5.8中使用了bash。

3 个答案:

答案 0 :(得分:5)

你可以使用像这样的文件描述符;

((date | tee >( wc >&3) | wc) 3>&1) | wc

((command1 | tee >( command2 >&3) | command3) 3>&1) | command4

要解释,即tee >( wc >&3)将在stdout上输出原始数据,内部wc将在FD 3上输出结果。外部3>& 1)将合并FD3输出返回STDOUT,因此两个wc的输出都被发送到拖尾命令。

然而,这个管道(或你自己的解决方案中的那个)中没有任何东西可以保证输出不会被破坏。这是来自command2的不完整的行不会与command3的行混淆 - 如果这是一个问题,你将需要做两件事之一;

  1. 编写自己的tee程序,在内部使用popen并在将完整行发送到stdout之前读取每一行,以便command4读取
  2. 将command2和command3的输出写入文件,并使用cat将数据合并为command4的输入

答案 1 :(得分:0)

另请参阅example。在所有答案中,我发现https://unix.stackexchange.com/questions/28503/how-can-i-send-stdout-to-multiple-commands特别适合我的需要。

扩大一点@Soren的回答,

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

您可以不使用tee而是环境变量,

$ ((date | tee >( wc >&3) | wc) 3>&1) | cat -n
     1         1       6      29
     2         1       6      29

就我而言,我应用了这种技术并编写了一个在busybox下运行的非常复杂的脚本。

答案 2 :(得分:0)

我相信您的解决方案是好的,它使用tee记录在案。 如果您阅读tee的联机帮助页,则会显示:

Copy standard input to each FILE, and also to standard output

您的文件是进程替换。

标准输出是您需要删除的,因为您不想要它,这就是将其重定向到/ dev / null

的过程