如何使用awk根据数值范围向列添加特定值

时间:2018-03-01 12:58:31

标签: bash awk

我正在尝试根据coverage_file中的数字向我的文件bed_file添加一列。在我的coverage_file中,我在第二列中有位置,bed_file包含第二列到第三列的位置范围以及第4列中的名称。我想为每个位置添加相应的名称到coverage_file范围内的bed_file并且还有编号,因此我可以区分同一对象(重叠群)上的多个位置范围。希望我的示例数据更清晰:

#example data

#coverage file looks like:

#k141_xxx.xx are contigs (long sequences of DNA), where different genes can be found on.
#the second column is the current position on the individual contig
#the third column is the coverage on this position (not important here)
#the fourth column is the sample where the data comes from: A1..7 and B8..10

k141_102288 298 5 A4
k141_102288 298 5 A5
k141_102288 298 5 B8
k141_102288 298 5 B9
k141_102288 299 5 A4
k141_102288 299 5 A5
k141_102288 299 5 B9
k141_102288 300 5 A5
k141_102288 301 5 A5
k141_102511.0 8226 5 A5
k141_102511.0 8227 5 A5
k141_102511.0 8228 5 A5
k141_102511.0 8229 5 A5
k141_102511.0 8230 5 A5
k141_102511.0 8231 5 A5
k141_102511.0 8232 5 A5
k141_102511.0 8233 5 A5
k141_102511.0 8234 5 A5
k141_102511.0 9129 5 A6
k141_102511.0 9207 5 A6
k141_102511.0 9275 5 A7
k141_102511.0 9276 5 A7
k141_102511.0 9277 5 A7
k141_102511.0 9278 5 A7
k141_102511.0 9279 5 A7
k141_102511.0 9280 5 A7
k141_102511.0 9281 5 A7
k141_102511.0 9282 5 A7
#bed file looks like this
# the bed file shows the start $2 and end $3 position of a gene $4 on the contigs $1
k141_102288 2   301 phnE
k141_102511.0   7890    8807    phnE
k141_102511.0   8814    10400   phnE
#proposed output (note the two different regions of phnE on k141_102511.0)
k141_102288 298 5 A4    phnE_001
k141_102288 298 5 A5    phnE_001
k141_102288 298 5 B8    phnE_001
k141_102288 298 5 B9    phnE_001
k141_102288 299 5 A4    phnE_001
k141_102288 299 5 A5    phnE_001
k141_102288 299 5 B9    phnE_001
k141_102288 300 5 A5    phnE_001
k141_102288 301 5 A5    phnE_001
k141_102511.0 8226 5 A5 phnE_002
k141_102511.0 8227 5 A5 phnE_002
k141_102511.0 8228 5 A5 phnE_002
k141_102511.0 8229 5 A5 phnE_002
k141_102511.0 8230 5 A5 phnE_002
k141_102511.0 8231 5 A5 phnE_002
k141_102511.0 8232 5 A5 phnE_002
k141_102511.0 8233 5 A5 phnE_002
k141_102511.0 8234 5 A5 phnE_002
k141_102511.0 9129 5 A6 phnE_003
k141_102511.0 9207 5 A6 phnE_003
k141_102511.0 9275 5 A7 phnE_003
k141_102511.0 9276 5 A7 phnE_003
k141_102511.0 9277 5 A7 phnE_003
k141_102511.0 9278 5 A7 phnE_003
k141_102511.0 9279 5 A7 phnE_003
k141_102511.0 9280 5 A7 phnE_003
k141_102511.0 9281 5 A7 phnE_003
k141_102511.0 9282 5 A7 phnE_003

我试图利用我之前的类似问题,但仍然无法弄清楚如何使其发挥作用:How to use info on substring position from one file to extract substring from another file (loop, bash)

有什么建议吗? 编辑: 我试着去建议没有。 2 by @ Nic3500,但我无法让它运行。我在最后一行有一个意外的令牌。这是我到目前为止所提出的:

#!bin/bash

# We are reading two files: coverage_file.txt and intersect.bed
# NR is equal to FNR as long as we are reading the
# first file.
# Store the positions in an array current_position from the coverage file (indexed by $1)
# go to bed file
# store the start and end positions and the gene names in similar arrays
# if current_position is between start_pos and end_pos, print additionally gene name 

awk 'NR==FNR{current_position[$1]=$2} 
NR==FNR{next}
{start_pos[$1]=$2;end_pos[$1]=$3;gene_name[$1]=$4}
{if(current_position[$1] >= start_pos[$1]) && (current_position[$1] <= `end_pos[$1]){ print $1,$2,$3,$4,gene_name[$1]}}' coverage_file.txt intersect.bed > test.txt`

1 个答案:

答案 0 :(得分:1)

awk救援!

 $ awk 'NR==FNR{start[NR]=$2; end[NR]=$3; key[$1,$2]=$4 sprintf("_%03d",NR); next}
           {for(i in start)
              {s=start[i];
               if(s<=$2 && $2<=end[i] && ($1,s) in key) print $0,key[$1,s]}}' bed coverage 

解释在读取第一个文件(NR==FNR部分)时,创建使用行号索引的数组以开始和结束范围。我们需要将范围与密钥相关联,因此创建一个用密钥索引的映射并为每个范围开始;这里也有机会使用行号计数器和最后一个字段作为标签创建索引标记,将数字格式化为零填充三位数。

为了处理第二个文件(现在是第二个语句),我们遍历所有开始查找匹配结束并验证密钥,范围开始是有效组合,打印添加了格式化后缀的行。

通过使用键索引起始值可以提高效率,但会使代码复杂化。如果你的“床”文件不是很大,应该不成问题。还有意打印所有匹配的条目,而不是第一个用于验证范围不重叠的条目。否则,离线进行验证并通过在第一次匹配/打印后断开来提高速度。此外,如果对起始值进行排序,则可以在错过起始范围时提前退出循环。