一行代码有两个临时文件(不是你想要的),如下所示:
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" vs. "++ /dev/fd/63" 或其他类似的内容,而不是两个编号的 fd。
即使是命名管道在文件系统中也不会出现,至少在 bash 可以使用类似于 "/dev/fd/63" 这样的文件名通过进程替换来实现的操作系统上不会出现。这样可以获得一个文件名,命令可以打开并从中读取,以实际从 bash 执行命令之前设置好的已打开文件描述符进行读取。(即 bash 在 fork 之前使用 pipe(2),然后使用 dup2 将输出从 quux 重定向到 diff 的输入文件描述符上,fd 为 63。)
在没有 "神奇" 的 / dev / fd 或 / proc / self / fd 的系统上,bash 可能会使用命名管道来实现进程替换,但它至少会自己管理它们,不像临时文件,您的数据不会写入文件系统。
您可以使用 echo <(true) 检查 bash 如何实现进程替换,以打印文件名而不是从中读取。在典型的 Linux 系统上,它会打印 /dev/fd/63。或者如果想要更多关于 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
mkfifo a; cmd >a& cmd2|diff a -; rm a
。 - unhammerpipeline1 | diff -u - <(pipeline2)
。然后输出将更清晰地提醒您哪个输入是哪个,通过显示-- /dev/stdin
vs.++ /dev/fd/67
或其他内容,而不是两个编号的文件描述符。 - Peter Cordesfoo <( pipe )
)不会修改文件系统。管道是匿名的,在文件系统中没有名称。Shell使用pipe
系统调用来创建它,而不是mkfifo
。如果您想亲自查看,请使用strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
跟踪文件和文件描述符系统调用。在Linux上,/dev/fd/63
是/proc
虚拟文件系统的一部分;它自动为每个文件描述符添加条目,并且它不是内容的副本。因此,除非foo 3<bar.txt
计数,否则不能将其称为“临时文件”。 - Peter Cordes