如何在不使用Bash中的临时文件的情况下diff两个管道?假设您有两个命令管道:
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
而不使用临时文件?
答案 0 :(得分:136)
带有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/stdin
与++ /dev/fd/63
或其他内容,而不是两个编号的fds。
甚至命名管道也不会出现在文件系统中,至少在操作系统中,bash可以通过使用/dev/fd/63
等文件名来实现进程替换,以获取命令可以打开的文件名,并从中读取实际读取的文件名。在执行命令之前bash设置的已打开文件描述符。 (即bash在fork之前使用pipe(2)
,然后dup2
从quux
的输出重定向到diff
的输入文件描述符,在fd 63上。)
在没有“魔法”/dev/fd
或/proc/self/fd
的系统上,bash可能会使用命名管道来实现进程替换,但与临时文件不同,它至少会自行管理它们,并且您的数据不会不要写入文件系统。
您可以检查bash如何使用echo <(true)
实现进程替换以打印文件名而不是从中读取。它在典型的Linux系统上打印/dev/fd/63
。或者有关bash使用的系统调用的详细信息,Linux系统上的此命令将跟踪文件和文件描述符系统调用
strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
如果没有bash,您可以创建命名管道。使用-
告诉diff
从STDIN读取一个输入,并使用命名管道作为另一个:
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
答案 1 :(得分:117)
在bash中,您可以使用子shell,通过将管道封闭在括号内来单独执行命令管道。然后你可以用&lt;创建匿名命名管道,然后传递给diff。
例如:
diff <(foo | bar) <(baz | quux)
匿名命名管道由bash管理,因此它们会自动创建和销毁(与临时文件不同)。
答案 2 :(得分:5)
到达此页面的某些人可能正在寻找逐行差异,而应使用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
区分开来。请注意,如果其中一个流是tail -f
,则无法通过进程替换来完成差异。
这是我写的关于在终端上传播流的blogpost,它引入了sd
。