将一个文件中的单个列条目与包含列表的第二个文件中的列条目相匹配

时间:2016-08-23 07:13:34

标签: shell awk

我需要将一个文件中的单个列条目与第二个文件中的列条目匹配,该文件由一个列表组成(在shell中)。我使用的awk命令只匹配列表的第一个单词,并且不扫描列字段中的整个列表。

文件1如下所示:

tabpanel.down('tabbar').move(0,1);

文件2如下所示:

chr1:725751 LOC100288069        
rs3131980   LOC100288069        
rs28830877  LINC01128       
rs28873693  LINC01128       
rs34221207  ATP4A       

预期产出:

Annotation Total Genes With Ann Your Genes  With Ann)   Your Genes  No Ann) Genome  With Ann)   Genome  No Ann) ln
1   path    hsa00190     Oxidative phosphorylation  55  55  1861    75  1139    5.9 9.64    0   0   ATP12A ATP4A ATP5A1 ATP5E ATP5F1 ATP5G1 ATP5G2 ATP5G3 ATP5J ATP5O ATP6V0A1 ATP6V0A4 ATP6V0D2 ATP6V1A ATP6V1C1 ATP6V1C2 ATP6V1D ATP6V1E1 ATP6V1E2 ATP6V1G3 ATP6V1H COX10 COX17 COX4I1 COX4I2 COX5A COX6B1 COX6C COX7A1 COX7A2 COX7A2L COX7C COX8A NDUFA5 NDUFA9 NDUFB3 NDUFB4 NDUFB5 NDUFB6 NDUFS1 NDUFS3 NDUFS4 NDUFS5 NDUFS6 NDUFS8 NDUFV1 NDUFV3 PP PPA2 SDHA SDHD TCIRG1 UQCRC2 UQCRFS1 UQCRH

(请原谅格式化 - 所有列都以制表符分隔,直到基因名称栏,14美元,称为基因组......)

我的命令是:

rs34221207  ATP4A hsa00190

非常感谢所有帮助!

1 个答案:

答案 0 :(得分:1)

您需要以其他顺序处理文件,并循环遍历列表:

awk 'NR==FNR{a[$2]=$1; next} {for(i=15;i<=NF;++i)if(a[$i]){print a[$i] "\t" $i "\t" $3}}' file1 file2

说明:

NR是一个全局“记录号”计数器,对于从每个文件读取的每一行,awk递增。 FNR是每个文件的“记录号”,awk在每个文件的第一行重置为1。因此NR==FNR条件对于第一个文件中的行为true,对于后续文件中的行为false。选择第一个文件信息是一个awk习惯用法。在这种情况下,a[$2]=$1存储由第二个字段文本键入的第一个字段文本。 next告诉awk停止当前行的短路并读取并继续正常处理下一行。第一个动作子句末尾的next在功能上类似于剩余代码上的ELSE条件,如果awk具有这样的语法(它没有):NR==FNR{a[$2]=$1} ELSE {for...。相反,NR==FNR{a[$2]=$1}NR!=FNR{for...可以更清晰,时间效率更低。

现在到第二个动作条款。在它之前没有任何条件意味着awk将为前面的next没有短路的每一行执行此操作,也就是说,除了第一个文件之外的所有行 - 仅在这种情况下为file2。您的file2有一个潜在密钥列表,从第15个字段开始并延伸到最后一个字段。最后一个字段编号的awk内置变量是NF(字段数)。 for循环非常不言自明,只循环那些字段数。对于这些数字i中的每一个,我们想知道该字段$i中的文本是否是第一个文件中的已知密钥 - a[$i]已设置,即评估为非-empty(非假)字符串。如果是这样,那么我们在a[$i]中有我们的file1第一个字段,在$i中有我们匹配的file1第二个字段,在$3中有我们感兴趣的file2字段(当前文件2的文本)第3场)。打印它们以制表符分隔。 next这里是一个仅限效率的度量,一旦找到匹配项就会停止对file2记录的所有处理。如果您的file2密钥列表可能包含重复项,并且您希望在这样的副本上存在重复的输出行,那么您必须删除最后一个next

实际上现在我再看一遍,你可能确实希望在非重复的情况下找到任何多个匹配,所以我从代码中删除了第二个next