【发布时间】:2013-01-06 12:59:27
【问题描述】:
我有两个文件(比如说a.txt 和b.txt),它们都有一个名称列表。我已经在这两个文件上运行了sort。
现在我想从a.txt 中找到b.txt 中不存在的行。
(我花了很多时间来寻找这个问题的答案,所以记录下来以备将来参考)
【问题讨论】:
标签: unix text-files
我有两个文件(比如说a.txt 和b.txt),它们都有一个名称列表。我已经在这两个文件上运行了sort。
现在我想从a.txt 中找到b.txt 中不存在的行。
(我花了很多时间来寻找这个问题的答案,所以记录下来以备将来参考)
【问题讨论】:
标签: unix text-files
你必须使用的命令不是diff而是comm
comm -23 a.txt b.txt
默认情况下,comm 输出 3 列:left-only、right-only、both。 -1、-2 和 -3 开关抑制这些列。
因此,-23 隐藏了 right-only 和 both 列,显示仅出现在第一个(左侧)文件中的行。
如果你想找到同时出现的行,你可以使用-12,它隐藏了 left-only 和 right-only 列,留给你只是 both 列。
【讨论】:
简单的答案对我不起作用,因为我没有意识到comm 匹配行,因此一个文件中的重复行将被打印为另一个文件中不存在。例如,如果 file1 包含:
Alex
Bill
Fred
文件2包含:
Alex
Bill
Bill
Bill
Fred
然后comm -13 file1 file2 会输出:
Bill
Bill
在我的例子中,我只想知道 file2 中的每个字符串都存在于 file1 中,而不管该行在每个文件中出现了多少次。
解决方案 1: 将 -u(唯一)标志用于 sort:
comm -13 <(sort -u file1) <(sort -u file2)
解决方案 2:(我找到的第一个“有效”答案)来自 unix.stackexchange:
fgrep -v -f file1 file2
请注意,如果 file2 包含 file1 中根本不存在的重复行,fgrep 将输出每个重复行。另请注意,我在一台笔记本电脑上对单个(相当大的)数据集进行的完全非科学测试表明,解决方案 1(使用 comm)比解决方案 2(使用 fgrep)快近 5 倍。
【讨论】:
fgrep 版本会很慢,如果你有几万行的话。
我不知道为什么有人说不应该使用diff。我会用它来比较两个文件,然后只输出左侧文件中的行,而不是右侧文件中的行。此类行由带有< 的 diff 标记,因此在行的开头使用 grep 符号就足够了
diff a.txt b.txt | grep \^\<
【讨论】:
diff --new-line-format= --unchanged-line-format= a.txt b.txt 来抑制新行和未更改行的打印。
如果文件还没有被排序,你可以使用:
comm -23 <(sort a.txt) <(sort b.txt)
【讨论】: