当前位置:  开发笔记 > 编程语言 > 正文

你如何在Bash中区分两个管道?

如何解决《你如何在Bash中区分两个管道?》经验,为你挑选了3个好方法。

如何在不使用Bash中的临时文件的情况下区分两个管道?假设您有两个命令管道:

foo | bar
baz | quux

而且你想diff在他们的输出中找到它们.一个解决方案显然是:

foo | bar > /tmp/a
baz | quux > /tmp/b
diff /tmp/a /tmp/b

是否可以在Bash中不使用临时文件的情况下这样做?您可以通过在其中一个管道中管道来消除一个临时文件:

foo | bar > /tmp/a
baz | quux | diff /tmp/a -

但是你不能同时将两个管道同时传输到diff中(至少不是以任何明显的方式).是否有一些聪明的技巧涉及/dev/fd不使用临时文件这样做?



1> VonC..:

带有2个tmp文件的单行(不是你想要的)将是:

 foo | bar > file1.txt && baz | quux > file2.txt && diff file1.txt file2.txt

使用bash,您可以尝试:

 diff <(foo | bar) <(baz | quux)

 foo | bar | diff - <(baz | quux)  # or only use process substitution once

第二个版本将更清楚地提醒您哪个输入是通过显示
-- /dev/stdinvs. ++ /dev/fd/63或什么,而不是两个编号的fds.


甚至命名管道也不会出现在文件系统中,至少在操作系统中,bash可以通过使用文件名来实现进程替换,例如/dev/fd/63获取命令可以打开的文件名并从中读取实际从已打开的文件描述符读取bash set在执行命令之前.(即bash pipe(2)在fork之前使用,然后在fd 63上dup2从输出重定向quux到输入文件描述符diff.)

在一个系统中没有"神奇" /dev/fd或者/proc/self/fd,庆典可能会使用命名管道实现进程替换,但它至少会管理它们本身,不像临时文件,和你的数据不会被写入到文件系统.

您可以检查bash如何实现进程替换echo <(true)以打印文件名而不是从中读取.它打印/dev/fd/63在典型的Linux系统上.或者有关bash使用的系统调用的更多详细信息,Linux系统上的此命令将跟踪文件和文件描述符系统调用

strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'

没有bash,你可以创建一个命名管道.使用-告诉diff从标准输入读一个输入,并使用命名管道作为其他:

mkfifo file1_pipe.txt
foo|bar > file1_pipe.txt && baz | quux | diff file1_pipe.txt - && rm file1_pipe.txt

请注意,您只能使用tee命令将一个输出传递给多个输入:

ls *.txt | tee /dev/tty txtlist.txt 

上面的命令显示ls*.txt到终端的输出,并将其输出到文本文件txtlist.txt.

但是通过流程替换,您可以使用tee将相同的数据提供给多个管道:

cat *.txt | tee >(foo | bar > result1.txt)  >(baz | quux > result2.txt) | foobar


即使没有bash,你也可以使用临时的fifo的`mkfifo a; cmd> a&cmd2 | diff a - ; rm a`

2> BenM..:

在bash中,您可以使用子shell,通过将管道括在括号内来单独执行命令管道.然后,您可以使用<来创建匿名命名管道,然后将其传递给diff.

例如:

diff <(foo | bar) <(baz | quux)

匿名命名管道由bash管理,因此它们会自动创建和销毁(与临时文件不同).


这在Bash中称为[进程替换](https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html).

3> mlg..:

到达此页面的某些人可能正在寻找逐行比较,comm或者grep -f应该使用逐行比较。

要指出的一件事是,在所有答案的示例中,差异只有在两个流都完成后才真正开始。使用以下方法进行测试:

comm -23 <(seq 100 | sort) <(seq 10 20 && sleep 5 && seq 20 30 | sort)

如果这是一个问题,您可以尝试sd(流差异),它不需要排序(就像comm上面的例子一样),也不需要像上面的示例那样进行过程替换,它比grep -f 无数流快几个数量级或数量级,并且支持无限流。

我建议的测试示例将这样编写sd

seq 100 | sd 'seq 10 20 && sleep 5 && seq 20 30'

但是不同之处在于马上seq 100就会有所不同seq 10。请注意,如果流之一是a tail -f,则差异不能通过进程替换来完成。

这是我写的关于在终端上分散流的博客文章,其中介绍了sd

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有