我有两个不同的文件,我想要部分匹配第一个文件中的一个数字与另一个文件中的另一个数字,并提取整列。
文件1:
smt_hsa_3150 932
smt_hsa_28592 682
smt_hsa_5184 657
smt_hsa_430 648
smt_hsa_14100 648
smt_hsa_96 648
文件2:
chr11 5933549 5933577 29 + hsa_smt_028592
chr11 45693060 45693086 27 - hsa_smt_000059
chr11 45699803 45699832 30 - hsa_smt_000087
chr2 131291172 131291197 26 - hsa_smt_000096
我需要将smt_hsa_28592或28592与hsa_smt_028592或028592匹配。 然后将第二个文件中的行与第一个文件的第二列中的行提取到一个新文件中。
输出:
chr11 5933549 5933577 29 + hsa_smt_028592 682
chr2 131291172 131291197 26 - hsa_smt_000096 648
由于我是awk / sed编程的新手,因此我首先尝试将第一个文件的第一列的名称从smt_hsa_3150更改为hsa_smt_3150,但是在执行
awk '{gsub("smt","hsa")}1'
然后,我不能使用相同的代码仅更改第二个“ hsa”。 第二个问题是如何将hsa_smt_028592与smt_has_28592或smt_hsa_96与hsa_smt_000096进行匹配。
答案 0 :(得分:1)
为了有趣的加入:
join -11 -26 -o 2.1,2.2,2.3,2.4,2.5,1.1,1.2 <(awk -F' +|_' '{printf "hsa_smt_%06s %s\n", $3, $4}' file1.txt | sort -k1) <(sort -k6 file2.txt)
awk命令以与file2相同的格式格式化file1的第一列。然后,我们将两个文件合并在一起(首先我们需要对它们进行排序)。
awk -F' *|_'
->我在多个空格和“ _”字符处分开
'{printf "hsa_smt_%06s %s\n", $3, $4}'
->我将hsa_smt_ <第三列打印为宽度6> <第4列>的整数。 Awk会在需要时添加前导零
sort -k6 file2
或awk ... | sort -k1
我对第6列或第1列的文件进行排序
join -11 -26 -o 2.1,2.2,2.3,2.4,2.5,1.1,1.2
我将文件1(-11
)的第一列和文件2(-26
)的第六列中的文件合并在一起,然后对列(2.1
进行排序-> file2的第一列,依此类推...)
纯awk解决方案:
awk 'NR==FNR{split($1,s,"_");smt[s[3]+0]=$2;next}{split($6,s,"_");k=s[3]+0}k in smt{print $0, smt[k]}' file1.txt file2.txt
在此解决方案中,我将smt_hsa_xxx和hsa_smt_xxx分开,将第三部分转换为整数,以便可以进行比较。
NR==FNR{split($1,s,"_");smt[s[3]+0]=$2;next}
由于NR==FNR
condition,仅在文件1上执行此块。它将第一列拆分,将smt_hsa id转换为整数(执行+0是将字符串在awk中转换为整数的经典方法),然后将第二列存储在名为smt的数组中。
next;
阻止执行文件1的其他块
{split($6,s,"_");k=s[3]+0}
此块将split file2的第六列,将id转换为整数。我们可以使用“ + | _”作为分隔符来避免拆分列(请参阅第一个解决方案)。
k in smt{print $0, smt[k]}
将检查id是否为smt数组的键。然后从文件2和文件1的第二列(存储在smt中)打印行
我很确定第二个解决方案的性能更高,但在内存中可能更贪婪。
两者的输出相同,行的顺序可能不同:
chr11 5933549 5933577 29 + hsa_smt_028592 682
chr2 131291172 131291197 26 - hsa_smt_000096 648