因为输入到join
必须排序,通常该命令的调用类似于:
join <(sort file1) <(sort file2)
这是不可移植的,因为它使用了 POSIX 未指定的进程替换。
join
-
还可以通过指定为文件参数之一来使用标准输入。然而,这仅允许排序一通过管道的文件:
sort file1 | join - <(sort file2)
似乎应该有一种简单的方法来完成对两个文件的排序,然后仅使用 POSIX 指定的功能连接结果。也许使用重定向到第三个文件描述符,或者可能需要创建一个 FIFO。然而,我很难想象它。
如何join
在未排序的文件上使用 POSIXly?
答案1
您可以使用两个命名管道来完成此操作(或者当然您可以使用一个命名管道和标准输入):
mkfifo a b
sort file1 > a &
sort file2 > b &
join a b
进程替换本质上是通过设置这些 fifo(/dev/fd/
在可用的情况下使用命名管道)来工作的。例如,在 bash 中:
$ echo join <(sort file1) <(sort file2)
join /dev/fd/63 /dev/fd/62
请注意 bash 如何用文件名(在/dev/fd
. (如果没有的话/dev/fd/
,足够新的 zsh、bash 和 ksh93 版本将使用命名管道。)调用时,它们会保持打开状态join
,因此当join
打开它们时,它将从两个sort
s 中读取。你可以看到它们通过了一些 lsof 技巧:
$ sh -c 'lsof -a -d 0-999 -p $$; exit' <(sort file1) <(sort file2)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sh 1894 anthony 0u CHR 136,5 0t0 8 /dev/pts/5
sh 1894 anthony 1u CHR 136,5 0t0 8 /dev/pts/5
sh 1894 anthony 2u CHR 136,5 0t0 8 /dev/pts/5
sh 1894 anthony 62r FIFO 0,10 0t0 237085 pipe
sh 1894 anthony 63r FIFO 0,10 0t0 237083 pipe
(这exit
是为了防止一种常见的优化,即当只有一个命令要运行时 shell 不会分叉)。