Shell 文本文件的交集与差集,交集(intersection)和差集(set difference)操作在数学课上的集合论中经常会被用到。有时候,也需要对字符串执行类似的操作。
预备知识
comm
命令可用于比较两个已排序的文件。它可以显示出第一个文件和第二个文件所独有的行以及这两个文件所共有的行。该命令有一些选项可以禁止显示指定的列,以便于执行交集和求差操作。
- 交集(intersection):打印出两个文件所共有的行。
-
求差(difference):打印出指定文件中所包含的互不相同的那些行。
-
差集(set difference)1:打印出包含在文件A中,但不包含在其他指定文件(例如B和C)中的那些行。
1假设现在有两个文件A和B,内容分别是:
A(1,2,3)
,B(3,4,5)
。那么,对这两个文件进行操作的结果如下。 交集:3
。 求差:1,2,4,5
。 差集(A
):1,2
。
实战演练
需要注意的是comm
必须使用两个排过序的文件作为输入。下面是我们用到的输入文件:
$ cat A.txt
apple
orange
gold
silver
steel
iron
$ cat B.txt
orange
gold
cookies
carrot
$ sort A.txt -o A.txt ; sort B.txt -o B.txt
(1) 首先执行不带任何选项的comm
:
$ comm A.txt B.txt
apple
carrot
cookies
gold
iron
orange
silver
steel
输出的第一列包含只在A.txt中出现的行,第二列包含只在B.txt中出现的行,第三列包含A.txt和B.txt中共有的行。各列之间以制表符(\t
)作为分隔符。
(2) 为了打印两个文件的交集,我们需要删除前两列,只打印出第三列。-1
选项可以删除第一列,-2
选项可以删除第二列,最后留下的就是第三列:
$ comm A.txt B.txt -1 -2
gold
orange
(3) 删除第三列,就可以打印出两个文件中互不相同的那些行:
$ comm A.txt B.txt -3
apple
carrot
cookies
iron
silver
steel
输出中包含着夹杂有空白的两列,显示了在file1和file2中存在的唯一的行。要想提高输出结果的可用性,可以将两列合并成一列,就像这样:
apple
carrot
cookies
iron
silver
steel
(4) 可以使用tr
(在第2章中讲到过)删除制表符来合并两列:
$ comm A.txt B.txt -3 | tr -d '\t'
apple
carrot
cookies
iron
silver
steel
(5) 通过删除不需要的列,我们就可以分别得到A.txt和B.txt的差集。
- A.txt的差集
$ comm A.txt B.txt -2 -3
-2 -3
删除第二列和第三列。
- B.txt的差集
$ comm A.txt B.txt -1 -3
-1 -3
删除第一列和第三列。
工作原理
comm
的命令行选项可以减少输出。
-1
:删除第一列。-
-2
:删除第二列。 -
-3
:删除第三列。
差集操作允许你比较两个文件,去掉两个文件中共有的行,打印出只在A.txt或B.txt中出现的那些行。当A.txt和B.txt作为comm
命令的参数时,输出中的第一列是A.txt相对于B.txt的差集,第二列是B.txt相对于A.txt的差集。
comm
命令还接受字符-
作为命令行参数,借此实现从stdin
中读取输入。这就提供了一种比较多个文件的方法。
假设我们有一个文件C.txt:
$> cat C.txt
pear
orange
silver
mithral
我们可以将文件B.txt和C.txt与A.txt相比较:
$> sort B.txt C.txt | comm - A.txt
apple
carrot
cookies
gold
iron
mithral
orange
pear
silver
steel