基于一列Awk合并两个文件

时间:2016-06-10 20:55:09

标签: awk

我正在尝试合并两个制表符分隔的文件文件 - 这些文件的长度不等。 我需要根据列号1合并文件,并从每个文件的第3列获取值到新文件。如果任何文件缺少任何id(不常见的值),那么它应该在新文件中得到一个空白值 -

File1: 
id1 2199 082
id2 0909 20909
id3 8002 8030
id4 28080 80828

File2:

id1 988 00808
id2 808 80808
id4 8080 2525
id6 838 3800

Merged file :

id1 082 00808
id2 20909 80808
id3 8030  
id4 80828 2525
id6   3800

我经历了很多论坛和帖子,到目前为止,我有这个

awk -F\t 'NR==FNR{A[$1]=$1; B[$1]=$1; next} {$2=A[$1]; $3=B[$1]}1'

但它没有产生正确的结果,任何人都可以建议。非常感谢!

4 个答案:

答案 0 :(得分:4)

$ awk -F'\t' 'NR==FNR{A[$1]=$3; next} {A[$1]; B[$1]=$3} END{for (id in A) print id,A[id],B[id]}' OFS='\t' File1 File2 | sort
id1     082     00808
id2     20909   80808
id3     8030
id4     80828   2525
id6             3800

如何运作

此脚本使用两个变量。对于File1中的每一行,关联数组A都有一个对应于id和第三个字段值的键。对于File2中的每个id,A也有一个键(但不一定是值)。对于File2,数组B具有每个id的键,其中包含来自第三列的相应值。

  • -F'\t'

    这会将输入中的字段分隔符设置为选项卡。请注意,必须引用\t以保护它免受外壳攻击。

  • NR==FNR{A[$1]=$3; next}

    这为第一个文件设置关联数组A

  • A[$1]; B[$1]=$3

    这为第二个文件设置关联数组。它还确保数组A具有file2中每个id的键。

  • END{for (id in A) print id,A[id],B[id]}

    打印出结果。

  • OFS='\t'

    这会将输出字段分隔符设置为选项卡。

  • sort

    不保证awk构造for key in array以任何特定顺序返回密钥。我们使用sort在id中按升序对输出进行排序。

答案 1 :(得分:4)

假设没有重复的ID,您可以尝试(在-F$'\t'使用Bash):

awk -F$'\t' 'BEGIN { OFS=FS } NR==FNR { A[$1] = $3; next }
             { if ($1 in A) print $1, A[$1], $3
               else         print $1, " ", $3
               delete A[$1]
             }
             END { for (i in A) print i, A[i], " " }
            ' File1 File2

设置输出字段分隔符。对于第一个文件中的行,捕获由列1索引的数组A中第一个文件的字段3.对于第二个(或后续)文件中的行,如果在A中找到ID列,打印三列;否则,在A中打印空格代替缺失的条目。使用完毕后删除A中的条目。最后,剩下的所有行都会打印出第二个文件中缺少的条目的空白。

对于给定的数据,输出的示例是:

id1     082     00808
id2     20909   80808
id4     80828   2525
id6             3800
id3     8030

显然,如果您希望以特定方式对数据进行排序,则可以使用awk命令对sort命令进行后置过滤(意味着将awk的输出传递给{ {1}})。

答案 2 :(得分:2)

另一个类似的awk

$ awk -v OFS='\t' 'NR==FNR{a[$1]=$3; next} 
                          {$2=$3; $3=a[$1]; delete a[$1]} 1;   
                       END{for(k in a) print k,"",a[k]} ' file2 file1

id1     082     00808
id2     20909   80808
id3     8030
id4     80828   2525
id6             3800

首先使用file2来匹配给定的输出但是不能保证订购,如果你的密钥有自然顺序,你可以按它们排序。

答案 3 :(得分:1)

使用sorted_in的GNU awk:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ a[$1] = (NR>FNR ? a[$1] OFS : "") $3 }
END {
    PROCINFO["sorted_in"] = "@ind_str_asc"
    for (k in a) {
        print k, a[k]
    }
}

$ awk -f tst.awk file1 file2
id1     082     00808
id2     20909   80808
id3     8030
id4     80828   2525
id6             3800

使用其他awk只需将输出传递给sort