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

Bash 如何使用awk根据数值范围向列添加特定值,bash,awk,Bash,Awk,我正试图根据bed_文件中的数字向我的文件coverage_文件中添加一列。在我的coverage_文件中,我的位置在第二列,bed_文件包含从第二列到第三列的位置范围以及第4列中的名称。我想将每个位置的对应名称添加到bed_文件范围内的coverage_文件中,并对其进行编号,以便能够区分同一对象重叠上的多个位置范围。希望我的示例数据更清楚: #example data #coverage file looks like: #k141_xxx.xx are contigs (long se

我正试图根据bed_文件中的数字向我的文件coverage_文件中添加一列。在我的coverage_文件中,我的位置在第二列,bed_文件包含从第二列到第三列的位置范围以及第4列中的名称。我想将每个位置的对应名称添加到bed_文件范围内的coverage_文件中,并对其进行编号,以便能够区分同一对象重叠上的多个位置范围。希望我的示例数据更清楚:

#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
我试图利用我以前遇到的一个类似问题,但仍然不知道如何解决:

有什么建议吗? 编辑: 我试着按照@Nic3500的第2条建议去做,但我无法让它运行。我在最后一行有一个意外的标记。这就是我到目前为止的想法:

#!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`
救命啊

 $ 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部分时,创建用行号索引的数组,以开始和结束范围。我们需要将范围与键关联起来,因此创建一个用键索引的映射,并从每个范围开始;这里还有机会使用行号计数器和最后一个字段作为标签创建索引标记,将数字格式化为零填充的三位数字

为了现在处理第二个file second语句,我们迭代所有的开始,找到匹配的结束并验证键,范围开始是有效的组合,打印添加了格式化后缀的行


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

建议:消除范围编号问题。创建一个临时床文件,并使用其中的编号更改名称。这样,您的编号就变成了行的编号,并且可以通过计数器和循环轻松实现。建议2:在覆盖率文件上循环,每行一行。提取行中的第二项。使用第二项,在bed_文件上循环,每行再循环一次。提取行的第二个和第三个元素。如果coverage\u file.seconditem>=bed\u file.secondelement和coverage\u file.seconditem@Nic3500:谢谢你的提示,我尝试了建议2,但无法运行,有什么改进的想法吗?我不是awk大师,我不会使用awk personnaly,尽管这与我缺乏知识有关,而不是工具的质量!。其他人将不得不在这一点上插嘴-@hek2mgl:无论如何,谢谢,也许是一些有awk经验的人已经帮助我来救我了-非常好用,谢谢!但我不太明白你到底在做什么,你能多评论一点吗?你必须问更具体的问题!我认为如果你知道awk的基本概念,它会读得很好。通用信息随处可见,包括本网站。是的,好吧,我不明白开始/结束[NR]在第一行中的作用是什么?密钥是两个文件之间的链接吗?我没有得到最后一个if条件&&&1,s,我看不出检查了什么?如果你能在上面加上一句话就太好了。太好了,谢谢!我将向循环中添加一些print语句,以查看内部到底发生了什么再次困扰您,我想我现在已经获得了您的大部分代码…但是为什么我们在第一行中有键[$1,$2]=$4?为什么要将bed文件中的第4列指定给两列?是否可以使用键[$2]作为指定sprintf_U03d,NR输出的字段?当我打印出键[$1]或键[$2]的内容时,它是空的,并且打印键[$1,$2]只返回一个值?这使我困惑;-我试着读懂它,但我发现在我甚至拥有这本书的大量awk文档中找到具体信息是有问题的。所以再一次,很抱歉今天太慢了。。。
#!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`
 $ 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