如何使用AWK基于两个文件之间的公共字段删除一个文件上的重复行?

时间:2010-12-08 01:35:13

标签: unix awk

我有两个文件

  1. 文件1包含3个字段

  2. 文件2包含4个字段

  3. 文件1的行数远小于文件2的行数

    我想基于第一个字段使用以下操作比较两个文件

    如果文件1的任何行中的第一个字段出现在文件2中行的第一个字段中,则不要为文件2打印该行。

    任何建议都会感激不尽。

    Input File 1
    
     S13109 3739 31082 
     S45002 3800 31873 
     S43722 3313 26638 
    
    Input File 2
    
     S13109 3738 31081 0 
     S13109 3737 31080 0 
     S00033 3008 29985 0 
     S00033 3007 29984 0 
     S00022 4130 31838 0 
     S00022 4129 31837 0 
     S00188 3317 27372 0 
     S45002 3759 31832 0 
     S45002 3758 31831 0 
     S45002 3757 31830 0 
     S43722 3020 26345 0 
     S43722 3019 26344 0 
     S00371 3737 33636 0 
     S00371 3736 33635 0 
    
    Desired Output
    
     S00033 3008 29985 0 
     S00033 3007 29984 0
     S00022 4130 31838 0 
     S00022 4129 31837 0 
     S00188 3317 27372 0
     S00371 3737 33636 0 
     S00371 3736 33635 0 
    

2 个答案:

答案 0 :(得分:6)

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

工作原理:

FNR==NR

当您有两个(或更多)输入文件到awk时,NR将在下一个文件的第一行重置为1,而FNR将从它停止的位置继续递增。通过检查FNR==NR,我们基本上检查我们当前是否正在解析第一个文件。

a[$1]++

如果我们 解析第一个文件(见上文),那么创建一个关联数组,第一个字段$1作为键,并将值递增1.这实质上让我们创建一个'看到'列表。

next

此命令告诉awk不要处理任何进一步的命令并读入下一条记录并重新开始。我们这样做是因为file1仅用于设置关联数组

!a[$1]

此行仅在FNR==NR为假时执行,即我们解析file1,因此必须解析file2。然后,我们使用file2的第一个字段$1作为索引到之前创建的“看到”列表的键。如果返回的值为0,则意味着我们没有在file1中看到它,因此我们应该打印这一行。相反,如果该值不为零,那么我们 在file1中看到它,因此我们打印它的值。请注意,!a[$1]相当于!a[$1]{print},因为未给出默认操作是打印整行。

答案 1 :(得分:1)

如果您不需要保留行的顺序,则可以在Bash,Korn shell或Z shell中使用进程替换以及joinsort实用程序:

join -v 2 <(sort file_1) <(sort file_2)

如果您使用的是没有进程替换的shell,则必须对文件进行预排序。