如果我们想要diff两条命令的输出,一种容易想到的做法是将两条命令的输出分别重定向到两个文件中,然后diff两个文件的内容:
$ readelf -WS ./a.out > a.txt
$ readelf -WS ./a.out.full > b.txt
$ diff a.txt b.txt
而bash
的Process Substitution机制可以帮助我们简化类似上面这类工作,把三条命令合并成一条:
$ diff <(readelf -WS ./a.out) <(readelf -WS ./a.out.full)
process substitution有两种形式:
<(command)
>(command)
其中第一种比较常用,它会创建一个文件(实际上是一个命名管道),command
的标准输出会被重定向到这个文件中,然后<(command)
整体会被替换为这个文件路径,我们可以从下面的命令以及输出中观察上述过程:
$ echo <(ls)
/dev/fd/63$ file <(ls)
/dev/fd/63: symbolic link to pipe:[9008834]$ ls -lh <(ls)
lr-x------ 1 root root 64 May 12 14:32 /dev/fd/63 -> ‘pipe:[9008840]’$ cat <(ls)
a.out
a.out.full
a.txt
b.txt
main.cpp
使用echo
命令将传给它的命令行参数进行输出,我们看到<(ls)
被替换成了一个文件,/dev/fd/63
。使用file
和ls
检查这个文件,发现它是一个符号链接,指向一个管道。使用cat
输出这个文件的内容,可以看出来正是ls
命令标准输出的内容。
process substitution的第二种形式>(command)
同样也会创建一个文件,并且整体同样会被替换为这个文件的路径。与第一种形式不同的地方在于,command
命令会把这个文件中的内容作为标准输入使用,而不是把标准输出重定向到这个文件。
第二种形式通常要与重定向配合使用,就像这样:
$ls > >(tee)
ls
命令会将标准输出重定向到一个临时创建的命名管道中,这个命名管道中的内容会作为tee
命令的标准输入,而tee
命令会把标准输入原样打印到标准输出,因此你最终会看到ls
的输出。
而这样使用是没有什么意义的:
$ls >(tee)
你只会看到>(tee)
被替换成的文件路径:
/dev/fd/63