我正在处理一个带有几个分支点并随后合并的管道-它们看起来像这样:

         command2
        /        \
command1          command4
        \        /
         command3

每个命令都写入STDOUT,并通过STDIN接受输入。必须将来自command1的STDOUT传递给command2和command3,它们依次运行,并且它们的输出必须有效地串联起来并传递给command4。我最初以为这样的事情会起作用:
$ command1 | (command2; command3) | command4

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

但令人惊讶的是,这也没有起作用-似乎将command1的输出和command2的输出通过管道传递到command3,这会导致错误,并且仅将command3的输出传递到command4。我的确发现以下内容与command2和command3之间有适当的输入和输出:
$ command1 | tee >(command2) >(command3) | command4

但是,这也会将command1的输出流式传输到command4,这会导致问题,因为command2和command3产生的规范不同于command1。我到达的解决方案似乎很棘手,但确实有效:
$ command1 | tee >(command2) >(command3) > /dev/null | command4

这样可以抑制command1将其输出传递给command4,同时从command2和command3收集STDOUT。它可以工作,但是我感觉缺少一个更明显的解决方案。是吗我已经阅读了数十个线程,还没有找到适用于我的用例的解决方案,也没有看到关于拆分和重新加入流的确切问题的详细说明(尽管我不能成为第一个)一个来解决这个问题)。我应该只使用命名管道吗?我尝试过,但是也很难使它正常工作,所以也许这是另一个话题的另一个故事。我在RHEL5.8中使用bash。

最佳答案

您可以像这样使用文件描述符。

((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的行混在一起-如果这是一个问题,您将需要做以下两件事之一;
  • 编写自己的tee程序,该程序在内部使用popen并读回每一行,然后将完整的行发送到stdout以供command4读取
  • 将command2和command3的输出写入文件,并使用cat将数据合并为command4的输入
  • 关于bash - 如何从多个进程中拆分并重新加入STDOUT?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23255841/

    10-13 03:36