在公共列上合并两个文件并使用awk打印所有列

时间:2018-08-07 12:11:27

标签: bash unix join awk

我有两个很长的空格分隔文件,看起来像这样:

文件1:

CHR SNP   A1 A2 MAF
1    rs12  A G  0.43
1    rs1   A T  0.22
1    1:30  G A  0.012
1    rs23  G A  0.012

文件2:

SNP    CHR A1 A2 MAF CHR:BP
rs21   1   G  A  0.03 1:30
rs13   1   T  A  0.06 1:122
rs23   1   A  G  0.02 1:234

当文件1的第2列适合文件2的第1列或文件2的第6列并同时打印两个文件的所有列时,我想将它们合并在一起。

因此示例的输出应为: 文件3

SNP  CHR A1 A2 MAF CHR:BP CHR SNP  A1 A2 MAF
rs21 1   G  A  0.03 1:30   1  1:30 G  A  0.012
rs23 1   A  G  0.02 1:234  1  rs23 G  A  0.012

我使用了以下代码:

awk 'NR==FNR{a[$2]=$0;next} ($1 in a || $6 in a){print $0 FS a[$2]}' file1 file2 > file3

但是由于某种原因,它会过滤掉正确的行,但只打印file2的列,而不打印file1的列。

我也尝试了join,但是即使文件被排序,它也给我带来奇怪的结果。奇怪的意思是,它忽略了两个文件中实际存在的大约1/5的行。只是为了完成,这是我尝试使用join的代码:

join -1 2 -2 1 -o '2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.14 2.15 1.1 1.2 1.3 1.4 1.5 1.6' <(sort -k2 file1) <(sort -k1 file2) > file3.1

join -1 2 -2 6 -o '2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.14 2.15 1.1 1.2 1.3 1.4 1.5 1.6' <(sort -k2 file1) <(sort -k6 file2) > file3.2

cat file3.1 file 3.2 > file3

有人看到我的错误吗?我将非常感激。 谢谢!

2 个答案:

答案 0 :(得分:2)

您的错误出在您的print命令中:

{print $0 FS a[$2]}

应该是

{print $0, ( $1 in a ? a[$1] : a[$6] )}

因为(1)当您在文件1中时,“有趣的”字段仅在$2中,而在遍历file2时不存在,并且(2)您需要从基于数组的数组中提取数据在任何一个条件下我们可以使用经典的三元运算符选择哪个数组元素。 (为了方便阅读,我添加了额外的间距。)

请注意使用逗号,逗号用OFS分隔字段,而不是使用FS作为输入字段分隔符。

否则,您的代码对我来说很好。

答案 1 :(得分:1)

请您尝试以下。

awk 'FNR==NR{a[$2]=$0;next} ($1 in a) || ($6 in a){print $0,a[$1]?a[$1]:a[$6]}'  Input_file1  Input_file2

也在此处添加非单一衬里形式的解决方案。

awk '
FNR==NR{
  a[$2]=$0
  next
}
($1 in a) || ($6 in a){
  print $0,a[$1]?a[$1]:a[$6]
}'  Input_file1   Input_file2

> file3附加到上面的内容中,以将输出输入到file3。

编辑: 现在也为OP的代码添加解决方案。

awk 'NR==FNR{a[$2]=$0;next} ($1 in a || $6 in a){print $0 FS a[$1]?a[$1]:a[$6]}' file1 file2 > file3