使用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"])]
}
我有两个文件。
文件 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"])]
}