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

时间:2011-01-17 19:56:44

标签: linux perl bash scripting command-line

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

文本文件1包含:

1
2
3
4
5

文本文件2包含:

6
7
1
2
3
4

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

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

非常感谢!

8 个答案:

答案 0 :(得分:45)

$ 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]才属实
  • 如果上述模式返回true,则打印文本行,这是未给出明确操作时的默认awk行为

答案 1 :(得分:14)

使用一些鲜为人知的实用程序:

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

这将输出重复项,因此如果3中有file1file2中有2 {},则仍会输出1 3。如果这不是您想要的,请将输出从sort传递到uniq,然后再将其写入文件:

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

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

答案 2 :(得分:8)

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

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倍)。
  • comm略快于join
  • 如果file1和file2已经排序,commjoin比awk1 + awk2快得多。 (当然,他们不会假设已排序的文件。)
  • 据说,
  • awk1 + awk2使用更多的RAM和更少的CPU。 comm的实际运行时间较低,可能是因为它使用了更多的线程。 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

BTW,对于awkies:似乎a[$0]=1a[$0]++快,而(!($0 in a))(!a[$0])快。因此,对于awk解决方案,我建议:

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

答案 3 :(得分:5)

使用grep:

grep -F -x -v -f file_1 file_2 

答案 4 :(得分:5)

怎么样:

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

这将打印file_2中不在file_1中的条目。对于相反的结果,只需要替换&#39;&gt;&#39;用&#39;&lt;&#39; &#39;切&#39;删除由&#39; diff&#39;添加的前两个字符,这些字符不属于原始内容。

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

答案 5 :(得分:2)

这是另一个awk解决方案

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

答案 6 :(得分:1)

cat file1 file2 | sort -u > unique

答案 7 :(得分:0)

如果你确实设置了从命令行执行此操作,this site(搜索“找不到重复项”)有一个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)时间复杂度,但它可以完成这项工作。