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

Pet*_*ter 8 bash stdin stdout pipe tee

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

         command2
        /        \
command1          command4
        \        /
         command3
Run Code Online (Sandbox Code Playgroud)

每个命令都写入STDOUT并通过STDIN接受输入.STDOUT从命令1需要传递到两个命令2和命令3,这是运行顺序,以及它们的输出需要被有效地连接起来,并传递给command4.我最初认为像这样的东西会起作用:

$ command1 | (command2; command3) | command4
Run Code Online (Sandbox Code Playgroud)

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

$ command1 | tee >(command2) | command3 | command4
Run Code Online (Sandbox Code Playgroud)

但出乎意料的是没有工作,要么-似乎是command1输出命令2的输出通过管道输送到指令代码,从而导致错误,只有指令代码的输出管道输送到command4.我确实发现以下内容从command2和command3获取适当的输入和输出:

$ command1 | tee >(command2) >(command3) | command4
Run Code Online (Sandbox Code Playgroud)

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

$ command1 | tee >(command2) >(command3) > /dev/null | command4
Run Code Online (Sandbox Code Playgroud)

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

Sor*_*ren 6

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

((date | tee >( wc >&3) | wc) 3>&1) | wc
Run Code Online (Sandbox Code Playgroud)

要么

((command1 | tee >( command2 >&3) | command3) 3>&1) | command4
Run Code Online (Sandbox Code Playgroud)

解释一下,tee >( wc >&3)它将在stdout上输出原始数据,内部wc将在FD 3上输出结果。外部3>&1)然后将FD3输出合并回STDOUT,因此将两个wc的输出发送到tailing命令。

但是,该管道(或您自己的解决方案中的管道)中没有任何东西可以保证不会损坏输出。那就是来自command2的不完整的行不会与command3的行混在一起-如果这是一个问题,则您需要做以下两件事之一;

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