使用awk从基于另一个文件的文件中提取行

Extracting rows from file based on another file using awk

我有两个文件。

文件 1:

SNP Allele1 Allele2 Effect  StdErr  PVAL    Direction   HetISq  HetChiSHetDf    HetPVal
rs12266638  t   g   0.4259  0.0838  3.776e-07   +?  0.0 0.000   0   1
rs7995014   t   c   2.2910  0.5012  4.853e-06   +?  0.0 0.000   0   1

文件 2:

Chromosome Position SNP EA NEA EAF BETA SE P Direction
10 108627406 rs12266638 t g 0.991 -0.2649 0.0578 4.608e-06 -
11 116365828 rs112127824 a t 0.0327 0.4569 0.0994 4.327e-06 +

我想根据“SNP”列打印文件 3。如果 SNP 存在于文件 2 中,我想打印包含文件 1 的所有列的整行。

输出:

rs12266638  t   g   0.4259  0.0838  3.776e-07   +?  0.0 0.000   0   1

我尝试了以下方法:

awk 'FNR==NR{a[]=[=13=]; if(NR==1) print [=13=]} ( in a) {print a[]}' file 1 file 2 > file 3

但它打印的 SNP 与文件 2 中存在的不同。

你可以使用这个awk:

awk 'FNR==NR {a[]; next} FNR> 1 &&  in a' file2 file1

rs12266638  t   g   0.4259  0.0838  3.776e-07   +?  0.0 0.000   0   1

根据数据集的大小,这应该相当快,每个文件只访问一次。当然,不是在我目前可以比较的系统上,所以主要是预感。不过,这样的解决方案可能仅适用于唯一标识符的数量不是很大的情况。

#!/bin/bash
snp_expression=$(awk 'FNR>1{print }' file_2 | sort -u | paste -sd "|")
grep -E "^(${snp})[[:space:]]" file_1 > file_3

适用于 SNP 字段任何位置的更通用的解决方案:

# SO71009277.awk
BEGIN {
  fnr = 0
  while ((getline < ARGV[2]) > 0) {
    ++fnr
    if (fnr == 1) {
      for (i=1; i<=NF; i++)
        FIELDBYNAME2[$i] = i # e.g. FIELDBYNAME2["SNP"] = 3
    }
    else {
      SNP_KEY[$FIELDBYNAME2["SNP"]]
    }
  }
  close(ARGV[2])

  fnr = 0
  while ((getline < ARGV[1]) > 0) {
    ++fnr
    if (fnr == 1) {
      for (i=1; i<=NF; i++)
        FIELDBYNAME1[$i] = i # e.g. FIELDBYNAME1["SNP"] = 1
    }
    else {
      if ($FIELDBYNAME1["SNP"] in SNP_KEY)
        print [=10=]
    }
  }
  close(ARGV[1])
}

致电:

awk -f SO71009277.awk file1.txt file2.txt
=>
rs12266638  t   g   0.4259  0.0838  3.776e-07   +?  0.0 0.000   0   1

Ed Morton 编辑 - 如果您想使用更惯用的 awk 执行上述操作,则为:

FNR == 1 {
    for (i=1; i<=NF; i++) {
        fieldByName[(NR==FNR),$i] = i
    }
    next
}
NR == FNR {
    snpKey[$(fieldByName[1,"SNP"])] = [=12=]
    next
}
$(fieldByName[0,"SNP"]) in snpKey {
    print snpKey[$(fieldByName[0,"SNP"])]
}