提取2组/文件之间的唯一值

在linux / shell环境下工作,我该如何完成以下工作:

文本文件1包含:

1 2 3 4 5 

文本文件2包含:

 6 7 1 2 3 4 

我需要提取文件2中不在文件1中的条目。因此,在本例中为“6”和“7”。

我如何从命令行执行此操作?

非常感谢!

 $ awk 'FNR==NR {a[$0]++; next} !a[$0]' file1 file2 6 7 

代码如何工作的说明:

  • 如果我们正在处理file1,请跟踪我们看到的每一行文字。
  • 如果我们正在处理file2,并没有看到行文本,然后打印它。

详细说明:

  • FNR是当前文件的记录号码
  • NR是来自所有输入文件的当前整体记录编号
  • FNR==NR只有当我们正在读取file1时才是真的
  • $0是文本的当前行
  • a[$0]是一个散列,其中的键设置为当前文本行
  • a[$0]++跟踪我们已经看到的当前文本行
  • !a[$0]只有当我们没有看到行文字时, !a[$0]才是真的
  • 如果上述模式返回true,则打印文本行,这是未给出明确操作时的默认awk行为

使用一些鲜为人知的实用工具:

 sort file1 > file1.sorted sort file2 > file2.sorted comm -1 -3 file1.sorted file2.sorted 

这将输出重复的内容,所以如果file1有1 3 ,但是file2 2个,这仍然会输出1 3 。 如果这不是你想要的,那么在将它写入文件之前,通过uniq管道输出sort

 sort file1 | uniq > file1.sorted sort file2 | uniq > file2.sorted comm -1 -3 file1.sorted file2.sorted 

GNU coreutils软件包中有很多实用程序,允许进行各种文本操作。

我想知道以下哪个解决方案对于“更大”的文件是“最快”的:

 awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2 # awk1 by SiegeX awk 'FNR==NR{a[$0]++;next}!($0 in a)' file1 file2 # awk2 by ghostdog74 comm -13 <(sort file1) <(sort file2) join -v 2 <(sort file1) <(sort file2) grep -v -F -x -f file1 file2 

我的基准测试结果总之:

  • 不要使用grep -Fxf ,它会慢很多(在我的测试中是2-4次)。
  • commcomm稍快。
  • 如果file1和file2已经排序, commjoin比awk1 + awk2快得多。 (当然,他们不承担排序的文件。)
  • awk1 + awk2,据说,使用更多的RAM和更少的CPU。 通信的实际运行时间可能较低,原因是它使用更多的线程。 awk1 + awk2的CPU时间较短。

为了简洁起见,我省略了全部细节。 不过,我想任何有兴趣的人都可以联系我或者重复测试。 粗略地说,设置是

 # Debian Squeeze, Bash 4.1.5, LC_ALL=C, slow 4 core CPU $ wc file1 file2 321599 321599 8098710 file1 321603 321603 8098794 file2 

最快运行的典型结果

 awk2: real 0m1.145s user 0m1.088s sys 0m0.056s user+sys 1.144 awk1: real 0m1.369s user 0m1.324s sys 0m0.044s user+sys 1.368 comm: real 0m0.980s user 0m1.608s sys 0m0.184s user+sys 1.792 join: real 0m1.080s user 0m1.756s sys 0m0.140s user+sys 1.896 grep: real 0m4.005s user 0m3.844s sys 0m0.160s user+sys 4.004 

顺便说一句,对于awkies:似乎a[$0]=1a[$0]++快,并且(!($0 in a))(!a[$0])更快。 所以,对于awk解决方案,我建议:

 awk 'FNR==NR{a[$0]=1;next}!($0 in a)' file1 file2 

用grep:

 grep -F -x -v -f file_1 file_2 

怎么样:

 diff file_1 file_2 | grep '^>' | cut -c 3- 

这将打印file_2中不在file_1中的条目。 对于相反的结果,只需用'<'替换'>'即可。 'cut'删除由'diff'添加的前两个字符,这些字符不是原始内容的一部分。

这些文件甚至不需要排序。

这里是另一个awk解决方案

 $ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2 6 7 

如果你真的从命令行设置这个, 这个网站 (搜索“找不到重复”)有一个awk例子,搜索重复。 这可能是一个很好的起点。

不过,我鼓励你使用Perl或Python。 基本上,该计划的流程将是:

 findUniqueValues(file1, file2){ contents1 = array of values from file1 contents2 = array of values from file2 foreach(value2 in contents2){ found=false foreach(value1 in contents1){ if (value2 == value1) found=true } if(!found) print value2 } } 

这并不是最优雅的方式,因为它具有O(n ^ 2)的时间复杂度,但它可以完成这项工作。