如何删除一个文件中存在于另一个文件中的行?

How can I remove lines in one file that exist in another?

我每天都有一个文件,里面有 10,000 条记录,其中 99% 在最后一天的文件中。如何使用 macOS 命令行删除前一天文件中存在的较新文件中的行?

remove_duplicates newfile oldfile

这些文件看起来像这样:

"First Last"\t"email"\t"phone"\t"9 more columns..."

请注意,我尝试了 ,但它没有输出任何内容,即使我确认了重复的行。

就bash脚本而言,我能想到的解决方案是:

sort newfile | uniq | cat oldfile oldfile - | sort | uniq -u

细分:

  • sort newfile:对newfile中的行进行排序(uniq需要)
  • uniq:每个相同的行最多保留一个副本
  • cat oldfile oldfile -:读出oldfile两次并将上一次调用的输出附加到uniq
  • sort:根据 uniq
  • 的要求对行进行排序
  • uniq -u: 只保留恰好出现一次的行

由于oldfile被写了两次,oldfile中的每一行都将被uniq -u丢弃。您将留下仅出现在 newfile.

中的行

明显的注意事项:您的文件现在已排序,每个重复的行中只有一个。

comm 命令采用两个文件参数并打印三列:第一个文件唯一的行、第二个文件唯一的行以及两个文件中都出现的行。因此,如果您有两个文件,其中一个是另一个文件的副本加上几行,如下所示:

oldfile:

line1
line2
line3

newfile:

line1
line2
line3
line4
line5

您可以按如下方式使用comm

$ comm -13 oldfile newfile
line4
line5

其中 -13 代表 "suppress columns 1 and 3",即仅打印第二个文件独有的行。

comm 期望它的输入被排序,如果没有排序就会抱怨(至少 comm 的 GNU 版本是这样),但是如果你的文件真的是彼此的副本加上其中之一有多余的行,您可以取消该警告:

comm --nocheck-order -13 oldfile newfile

--nocheck-order 仅存在于 GNU comm 中,它是 GNU coreutils 的一部分(例如可以通过 homebrew 安装)。

如果关于文件未排序的警告是一个显示停止器并且输出行的顺序无关紧要,您还可以对输入文件进行排序:

comm -13 <(sort oldfile) <(sort newfile)

您可以将 grep-v(反转匹配)和 -f(文件)选项一起使用:

grep -v -f oldfile newfile > newstrip

它匹配 newfile 中不在 oldfile 中的任何行,并将它们保存到 newstrip.如果您对结果感到满意,之后您可以轻松地进行操作:

mv newstrip newfile

这将用 newstrip 覆盖 newfile(删除 newstrip)。