使用 POSIX 连接两个未排序的文件?

使用 POSIX 连接两个未排序的文件?

因为输入到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打开它们时,它将从两个sorts 中读取。你可以看到它们通过了一些 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 不会分叉)。

相关内容