基于一列Awk合并两个文件
我正在尝试合并两个以制表符分隔的文件-它们的长度不等。 我需要根据第1列合并文件,并从每个文件的第3列中获取新文件的值。如果任何文件缺少任何id(不常见值),则应在新文件中获得一个空值-基于一列Awk合并两个文件,awk,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 00
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'
但它并没有产生正确的结果,请任何人提出建议。非常感谢
$ 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
工作原理
此脚本使用两个变量。对于文件1中的每一行,关联数组A
都有一个键,对应于第三个字段的id和值。对于文件2中的每个id,A
也有一个键(但不一定是值)。对于文件2,数组B
对每个id都有一个键,该键具有第三列中的相应值
这会将输入时的字段分隔符设置为选项卡。请注意,必须引用-F'\t'
,以保护它不受外壳的影响\t
这将为第一个文件设置关联数组NR==FNR{A[$1]=3;next}
A
这将为第二个文件设置关联数组。它还确保数组A[$1];B[$1]=$3
对文件2中的每个id都有一个键A
这会打印出结果END{for(A中的id)打印id,A[id],B[id]}
- OFS='\t' 这会将输出字段分隔符设置为选项卡
数组中键的awk构造排序
不保证以任何特定顺序返回键。我们使用
在id中将输出按升序排序sort
-F$'\t'
):
设置输出字段分隔符。对于第一个文件中的行,捕获由列1索引的数组A
中第一个文件的字段3。对于第二个(或后续)文件中的行,如果在A
中找到ID列,则打印三列;否则,请在a
中打印一个空白项以代替缺少的条目。使用后删除A
中的条目。最后,剩余的任何行都会打印为空白,以显示第二个文件中缺少的条目
对于给定数据,输出示例如下:
id1 082 00808
id2 20909 80808
id4 80828 2525
id6 3800
id3 8030
显然,如果您希望以特定的方式对数据进行排序,可以使用
sort
命令对awk
命令进行后期筛选(这意味着将awk
的输出通过管道输送到sort
)。另一个类似的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
首先使用文件2匹配给定的输出,但不能保证顺序,如果您的键具有自然顺序,则可以按它们进行排序。使用GNU awk for
排序
:
$ 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,只需通过管道将输出传输到
排序
无需$'\t'
使其特定于bash,在本例中,awk会根据需要扩展'\t'
。谢谢Jonathan,我不需要按排序顺序显示结果,因此也可以正常工作!非常感谢约翰!它工作得非常完美,您的解释真的有助于理解如何修改命令。非常感谢karakfa。现在我有两个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