awk:如何从文件A中提取文件B中指定索引的列?

时间:2014-12-18 20:21:27

标签: bash unix awk

我的文件A 的格式如下,包含数十万列和数千行:

1000->100001    DOSE    2.000   2.000   2.000   2.000   2.000 ....
1001->100101    DOSE    1.988   1.988   2.000   2.000   2.000 ....
1001->100101    DOSE    1.933   2.000   2.000   2.000   2.000 ....
1002->100201    DOSE    2.000   2.000   2.000   2.000   2.000 ....
1002->100201    DOSE    2.000   2.000   2.000   2.000   2.000 ....

虽然我的文件B (数千个条目)具有以下格式:

SNP,Al1,Al2,Freq1,MAF,AvgCall,Rsq,Genotyped,key,pos,gene_key
20:29649365,C,T,0.93021,0.06979,0.93021,0.10115,,803428,29649365,12
20:29649737,A,G,0.93914,0.06086,0.93914,0.14303,,803442,29649737,12
20:29649765,T,G,0.99963,0.00037,0.99963,0.13918,,803443,29649765,12
20:29650462,A,T,0.89387,0.10613,0.89388,0.12864,,803456,29650462,12

我想要做的是从文件A中提取前两列以及文件B中“key”列中指定的列。我花了一些时间试图弄清楚如何使用awk这样做,但它一直在服用对理论上不应该太困难的事情来说太长了。

我的具体问题是:一旦我从文件B中提取“密钥”条目,我如何将这些值传递给文件A的awk命令?

文件B中前3列的手动命令:

awk '{print $1, $2, $803428, $803442, $803442}' fileA > output.txt 

编辑:

文件A 文件B 之间没有公共列。 文件A 中第803428列中的值表示来自文件B 的SNP“20:29649365”的结果。

如果要运行的命令是:

awk '{print $1, $2, $3, $4, $5}' fileA

结果将是:

1000->100001 DOSE 2.000 2.000 2.000 2.000 2.000
1001->100101 DOSE 1.988 1.988 2.000 2.000 2.000
1002->100201 DOSE 1.933 1.999 2.000 2.000 2.000
1003->100301 DOSE 2.000 2.000 2.000 2.000 2.000
1004->100401 DOSE 2.000 2.000 2.000 2.000 2.000

我用来测试作为解决方案提供的awk命令的具体示例。

的fileA:

1000->100001    DOSE    2.000   2.000   2.000   2.000   2.000
1001->100101    DOSE    1.988   1.988   2.000   2.000   2.000
1001->100101    DOSE    1.933   2.000   1.500   2.000   2.000
1002->100201    DOSE    2.000   2.000   2.000   2.000   1.622
1002->100201    DOSE    2.000   2.000   2.000   2.000   2.000

FILEB:

SNP,Al1,Al2,Freq1,MAF,AvgCall,Rsq,Genotyped,key,pos,gene_key
20:29649365,C,T,0.93021,0.06979,0.93021,0.10115,,3,29649365,12
20:29649737,A,G,0.93914,0.06086,0.93914,0.14303,,4,29649737,12
20:29650462,A,T,0.89387,0.10613,0.89388,0.12864,,6,29650462,12

所需的输出(第1,2,3,4,6列 - 来自fileB的键列的最后3列):

1000->100001    DOSE    2.000   2.000   2.000
1001->100101    DOSE    1.988   1.988   2.000
1001->100101    DOSE    1.933   2.000   2.000
1002->100201    DOSE    2.000   2.000   2.000
1002->100201    DOSE    2.000   2.000   2.000

3 个答案:

答案 0 :(得分:3)

如果你想从fileB(key列,而不是pos)读取列索引并从fileA打印那些列,也保持col索引在fileB中的顺序,你可以尝试:

awk 'NR==FNR{c[NR]=$(NF-2);n=NR;next}
{printf "%s %s",$1,$2;
for(i=2;i<=n;i++)printf " %s",$c[i];print ""}' FS=',' fileB FS=' ' fileA

答案 1 :(得分:3)

好的,这是一个应该重现输出的更新版本。

awk 'ARGIND==2&&!/SNP/{cols[++i]=$9}ARGIND==4{printf("%s %s",$1,$2);
      for(j=1;j<=i;j++)printf(" %s%s",$cols[j],j<i?"":"\n");}' FS=',' B.txt FS='[ \t]+' A.txt 

两个文件中的不同字段分隔符和B文件中的标题必须被忽略,这有点复杂。但关键是$接受一个变量,而不仅仅是一个常数整数。此方法将列列表存储在cols数组中,并针对A中的每一行迭代它们。

在文件之间切换字段分隔符是通过虚拟文件FS=','和&#39; FS =&#39; [\ t] +&#39;`来完成的,这意味着我们的实际文件已经过了2和4.

答案 2 :(得分:1)

替代方法:在fileB上应用awk脚本生成另一个awk脚本,以应用于fileA。

#!/bin/bash
awk -F, 'NR>1{a=a",$"$9}END{print"{print $1,$2"a"}"}' < fileB > cols.awk
awk -f cols.awk fileA

或者作为单行,没有中间文件:

#!/bin/bash
awk "$(awk -F, 'NR>1{a=a",$"$9}END{print"{print $1,$2"a"}"}' < fileB)" fileA