如何根据从第二个文件中获取的值范围排除文件中的行
How to exclude lines in a file based on a range of values taken from a second file
我有一个包含值范围列表的文件:
2 4
6 9
13 14
第二个文件如下所示:
HiC_scaffold_1 1 26
HiC_scaffold_1 2 27
HiC_scaffold_1 3 27
HiC_scaffold_1 4 31
HiC_scaffold_1 5 34
HiC_scaffold_1 6 35
HiC_scaffold_1 7 37
HiC_scaffold_1 8 37
HiC_scaffold_1 9 38
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 13 39
HiC_scaffold_1 14 39
HiC_scaffold_1 15 42
我想从文件 2 中排除第 2 列的值在文件 1 定义的范围内的行。理想的输出是:
HiC_scaffold_1 1 26
HiC_scaffold_1 5 34
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 15 42
我知道如何使用 awk 提取单个范围:
awk ' == "2", == "4"' file2.txt
但是我的文件 1 有很多范围值(行),我需要排除而不是提取与这些值对应的行。
这是一个错误:
$ awk '
NR==FNR { # first file
min[NR]= # store mins and maxes in pairs
max[NR]=
next
}
{ # second file
for(i in min)
if(>=min[i]&&<=max[i])
next
}1' ranges data
输出:
HiC_scaffold_1 1 26
HiC_scaffold_1 5 34
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 15 42
如果范围不是很大并且是整数值但数据很大,您可以制作一个值的排除映射以加速比较:
$ awk '
NR==FNR { # ranges file
for(i=;i<=;ex[i++]); # each value in the range goes to exclude hash
next
}
!( in ex)' ranges data # print if not found in ex hash
催眠
如果file2.txt
的第二列始终等于其行的索引,则可以使用sed
修剪这些行。如果这不是您的情况,请参阅 awkception 段落。
sed $(sed 's/^\([0-9]*\)[[:space:]]*\([0-9]*\)/-e ,d/' file1.txt) file2.txt
其中 file1.txt
包含您的范围,file2.txt
是数据本身。
基本上它构建了一个 sed
调用,链接了一个 -e i,jd
表达式列表,这意味着它将删除 ith 行和 第j行.
在您的示例中,sed 's/^\([0-9]*\)[[:space:]]*\([0-9]*\)/-e ,d/' file1.txt
将输出 -e 2,4d -e 6,9d -e 13,14d
,这是用于在 file2.txt
.
上调用 sed
的表达式列表
最后会调用:
sed -e 2,4d -e 6,9d -e 13,14d file2.txt
此命令删除第2和第4之间的所有行,第6和第9之间的所有行,以及第13和第14之间的所有行。
显然,如果 file2.txt
的第二列 不 匹配其自身行的索引,则它不起作用。
awkception
awk "{$(awk '{printf "if (>=%d && <=%d) next\n", , }' file1.txt)}1" file2.txt
即使第二列与其所在行的索引不匹配,此解决方案也有效。
该方法使用 awk
创建一个 awk
程序,就像 sed
在 sedception 中创建 sed
表达式一样解决方案。
最后这将调用:
awk '{
if (>=2 && <=4) next
if (>=6 && <=9) next
if (>=13 && <=14) next
}1' file2.txt
需要注意的是这个解决方案比sed
慢很多。
如果您的范围不大:
$ cat tst.awk
NR==FNR {
for (i=; i<=; i++) {
bad[i]
}
next
}
!( in bad)
$ awk -f tst.awk file1 file2
HiC_scaffold_1 1 26
HiC_scaffold_1 5 34
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 15 42
我有一个包含值范围列表的文件:
2 4
6 9
13 14
第二个文件如下所示:
HiC_scaffold_1 1 26
HiC_scaffold_1 2 27
HiC_scaffold_1 3 27
HiC_scaffold_1 4 31
HiC_scaffold_1 5 34
HiC_scaffold_1 6 35
HiC_scaffold_1 7 37
HiC_scaffold_1 8 37
HiC_scaffold_1 9 38
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 13 39
HiC_scaffold_1 14 39
HiC_scaffold_1 15 42
我想从文件 2 中排除第 2 列的值在文件 1 定义的范围内的行。理想的输出是:
HiC_scaffold_1 1 26
HiC_scaffold_1 5 34
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 15 42
我知道如何使用 awk 提取单个范围:
awk ' == "2", == "4"' file2.txt
但是我的文件 1 有很多范围值(行),我需要排除而不是提取与这些值对应的行。
这是一个错误:
$ awk '
NR==FNR { # first file
min[NR]= # store mins and maxes in pairs
max[NR]=
next
}
{ # second file
for(i in min)
if(>=min[i]&&<=max[i])
next
}1' ranges data
输出:
HiC_scaffold_1 1 26
HiC_scaffold_1 5 34
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 15 42
如果范围不是很大并且是整数值但数据很大,您可以制作一个值的排除映射以加速比较:
$ awk '
NR==FNR { # ranges file
for(i=;i<=;ex[i++]); # each value in the range goes to exclude hash
next
}
!( in ex)' ranges data # print if not found in ex hash
催眠
如果file2.txt
的第二列始终等于其行的索引,则可以使用sed
修剪这些行。如果这不是您的情况,请参阅 awkception 段落。
sed $(sed 's/^\([0-9]*\)[[:space:]]*\([0-9]*\)/-e ,d/' file1.txt) file2.txt
其中 file1.txt
包含您的范围,file2.txt
是数据本身。
基本上它构建了一个 sed
调用,链接了一个 -e i,jd
表达式列表,这意味着它将删除 ith 行和 第j行.
在您的示例中,sed 's/^\([0-9]*\)[[:space:]]*\([0-9]*\)/-e ,d/' file1.txt
将输出 -e 2,4d -e 6,9d -e 13,14d
,这是用于在 file2.txt
.
sed
的表达式列表
最后会调用:
sed -e 2,4d -e 6,9d -e 13,14d file2.txt
此命令删除第2和第4之间的所有行,第6和第9之间的所有行,以及第13和第14之间的所有行。
显然,如果 file2.txt
的第二列 不 匹配其自身行的索引,则它不起作用。
awkception
awk "{$(awk '{printf "if (>=%d && <=%d) next\n", , }' file1.txt)}1" file2.txt
即使第二列与其所在行的索引不匹配,此解决方案也有效。
该方法使用 awk
创建一个 awk
程序,就像 sed
在 sedception 中创建 sed
表达式一样解决方案。
最后这将调用:
awk '{
if (>=2 && <=4) next
if (>=6 && <=9) next
if (>=13 && <=14) next
}1' file2.txt
需要注意的是这个解决方案比sed
慢很多。
如果您的范围不大:
$ cat tst.awk
NR==FNR {
for (i=; i<=; i++) {
bad[i]
}
next
}
!( in bad)
$ awk -f tst.awk file1 file2
HiC_scaffold_1 1 26
HiC_scaffold_1 5 34
HiC_scaffold_1 10 39
HiC_scaffold_1 11 39
HiC_scaffold_1 12 39
HiC_scaffold_1 15 42