如何在Linux中将两个命名管道加入单个输入流


64

使用|Linux中的管道()功能,我可以将标准输入转发到一个或几个输出流。

我可以tee用来将输出拆分为单独的子流程。

是否有将两个输入流合并的命令?

我将如何处理?diff如何工作?

Answers:


105

就我个人而言,我最喜欢(需要bash和大多数Linux发行版中标准的其他功能)

详细信息在很大程度上取决于这两件事的输出以及您希望如何合并它们……

在输出中,命令1和命令2的内容依次排列:

cat <(command1) <(command2) > outputfile

或者,如果这两个命令输出的是您要并排查看的同一数据的替代版本(我将其与snmpwalk一起使用;一侧为数字,另一侧为MIB名称):

paste <(command1) <(command2) > outputfile

或者,如果您想比较两个相似命令的输出(例如在两个不同目录中查找)

diff <(command1) <(command2) > outputfile

或者,如果它们是某种排序的输出,则将它们合并:

sort -m <(command1) <(command2) > outputfile

或一次运行两个命令(不过可能会使事情有些混乱):

cat <(command1 & command2) > outputfile

<()运算符为每个命令设置一个命名管道(或/ dev / fd),将该命令的输出通过管道传递到该命名管道(或/ dev / fd文件句柄引用),并在命令行上传递该名称。>()等效。您可以这样做:例如command0 | tee >(command1) >(command2) >(command3) | command4,将一个命令的输出同时发送到另外4个命令。


太棒了!我读过bash的手册页大量的时间,但并没有挑选一个
哈维尔

2
您可以在Linux文档项目的[高级bash脚本指南](tldp.org/LDP/abs/html/process-sub.html)中找到该参考
brice 2011年

3
我能够通过grep --line-buffered-方便地同时grep处理tail多个日志文件来防止交错的行。参见stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO 2013年

16

您可以使用来将两个蒸汽附加到另一个cat,如大猩猩所示。

您还可以创建一个FIFO,将命令的输出定向到该FIFO,然后使用任何其他程序从FIFO中读取:

mkfifo ~/my_fifo
command1 > ~/my_fifo &
command2 > ~/my_fifo &
command3 < ~/my_fifo

对于仅将写入或读取文件的程序,或仅将stdout / file输出与仅支持另一种的程序混合使用的程序特别有用。


2
这适用于pfSense(FreeBSD),而接受的答案则无效。谢谢!
内森

9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1/tmp/p2是您的输入管道,/tmp/output而是输出。


6
注意:除非在一侧两个命令的()在每一行(和原子其他一些不起眼的POSIX规则)冲洗它们的输出,你可以用一些奇怪的扰码输入到猫结束了...
自由报

您不应该使用分号代替&字符吗?
萨米尔

这是史诗般的东西
Mobigital

5

我为此创建了特殊程序:fdlinecombine

它读取多个管道(通常是程序输出)并将它们按行写入stdout(您也可以覆盖分隔符)


如广告般运作。感谢您将其公开。
alexei 2015年


3

这里要小心;仅仅抓住它们将最终以您不想要的方式混合结果:例如,如果它们是日志文件,则您可能可能真的不希望从一个插入的行到另一个插入的行中间插入一行。如果可以的话

尾-f / tmp / p1 / tmp / p2> / tmp / output

将工作。如果这是不是好,那么你将不得不做找到的东西,会做行缓冲,只输出完整的生产线。Syslog可以做到这一点,但是我不确定还有什么可能。

编辑:无缓冲读取和命名管道的优化:

将/ tmp / p1,/ tmp / p2,/ tmp / p3视为命名管道,由“ mkfifo / tmp / p N ”创建

尾-q -f / tmp / p1 / tmp / p2 | awk'{print $ 0>“ / tmp / p3”; close(“ / tmp / p3”); fflush();}'&

现在,通过这种方式,我们可以读取输出缓冲为“ / tmp / p3”的管道:

尾巴-f / tmp / p3

有一个小错误,您需要通过以下方式“初始化”第一个输入管道/ tmp / p1:

回声-n> / tmp / p1

为了尾部将首先接受来自第二个管道/ tmp / p2的输入,而不要等到/ tmp / p1出现。事实并非如此,如果您确定/ tmp / p1将首先接收输入。

此外,还需要-q选项,以便尾部不打印有关文件名的垃圾。


更有用的是:“ tail -q -f / tmp / p1 / tmp / p2 | another_command”,因为它将逐行完成,并且使用-q选项将不会打印任何其他垃圾
readyblue 2014年

对于无缓冲的文件/命名管道使用: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & 现在/ tmp / p3甚至可以命名为管道,您可以通过以下方式读取它tail -f /tmp/p3UNBUFFERED =一行一行 ,但是存在一些小错误。第一个文件/命名管道需要首先初始化,以便tail接受第二个文件的输出。因此您将需要,echo -n > /tmp/p1并且随后一切都将顺利进行。
readyblue 2014年

1

最好的程序是lmerge。与freihart的答案不同,它是面向行的,因此这两个命令的输出不会互相干扰。与其他解决方案不同,它公平地合并了输入,因此没有命令可以控制输出。例如:

$ lmerge <(yes foo) <(yes bar) | head -n 4

提供以下内容的输出:

foo
bar
foo
bar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.