3.3 文本文件的交集与差集
交集(intersection)和差集(set difference)操作在集合论相关的数学课上经常会被用到。不过,对文本进行类似的操作在某些情况下也很有用。
3.3.1 预备知识
comm
命令可用于两个文件之间的比较。它有很多不错的选项可用来调整输出,以便我们执行交集、求差(difference)以及差集操作1。
1 假设现在有两个文件A和B,内容分别是:A(1,2,3)
,B(3,4,5)
。那么,对这两个文件进行操作的结果如下。
交集:3
求差:1,2,4,5
差集(A)
:1,2
。
交集:打印出两个文件所共有的行。
求差:打印出指定文件所包含的且不相同的那些行。
差集:打印出包含在文件A中,但不包含在其他指定文件中的那些行。
3.3.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
- $ comm A.txt B.txt
- apple
- carrot
- cookies
- gold
- iron
- orange
- silver
- steel
输出的第一列包含只在A.txt中出现的行,第二列包含只在B.txt中出现的行,第三列包含A.txt和B.txt中相同的行。各列以制表符(\t
)作为定界符。
有一些选项可以按照我们的需求进行格式化输出,例如:
-1
从输出中删除第一列;-2
从输出中删除第二列;-3
从输出中删除第三列。
为了打印两个文件的交集,我们需要删除第一列和第二列,只打印出第三列:
- $ comm A.txt B.txt -1 -2
- gold
- orange
打印出两个文件中不相同的行:
- $ comm A.txt B.txt -3
- apple
- carrot
- cookies
- iron
- silver
- steel
在comm
命令中用 -3
删除第三列,输出第一列和第二列。第一列包含那些只出现在A.txt中的行,第二列包含那些只出现在B.txt中的行。由于输出中只包含了两列,它在此处的用处也不大。对于每个唯一的行,在列中都会对应一个空白字段。因此在同一行上,两列的内容不会重复。为了获得一个可用的输出文本格式,我们需要将空白字段删除,把两列合成一列:
- apple
- carrot
- cookies
- iron
- silver
- steel
要生成这样的输出,就得删除行首的 \t
字符。可以用下面的方法删除 \t
,从而合并成单列:
- $ comm A.txt B.txt -3 | sed 's/^\t//'
- apple
- carrot
- cookies
- iron
- silver
- steel
sed
命令通过管道获取comm
的输出。它删除行首的 \t
字符。sed
中的s
表示替换(substitute)。/^\t/
匹配行前的 \t
(^
是行首标记)。//
(两个/操作符之间没有任何字符)是用来替换行首的\t
的字符串。如此一来,就删除了所有行首的\t
。
接下来讲解两个文件的差集操作。
差集操作允许你比较两个文件,并打印出只在A.txt或B.txt中出现的行。当A.txt和B.txt作为comm
命令的参数时,输出中的第一列是A.txt相对于B.txt的差集,第二列是B.txt相对于A.txt的差集。
通过删除不需要的列,我们就可以分别得到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
删除第一列和第三列。