我正在开发一个有一些分支点然后合并的管道 - 它们看起来像这样:
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。
答案 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的行混淆 - 如果这是一个问题,你将需要做两件事之一;
tee
程序,在内部使用popen并在将完整行发送到stdout之前读取每一行,以便command4读取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
的过程