![Bash:通过匹配数字范围来过滤行](https://linux22.com/image/126111/Bash%EF%BC%9A%E9%80%9A%E8%BF%87%E5%8C%B9%E9%85%8D%E6%95%B0%E5%AD%97%E8%8C%83%E5%9B%B4%E6%9D%A5%E8%BF%87%E6%BB%A4%E8%A1%8C.png)
我有一个文件测试与字段:卡托, 和位置。
1 7100
1 35000
1 49321
1 49759
2 44842
2 52794
2 53558
3 53859
3 54013
3 55172
我有一个文件D b与字段:卡托,开始和停止。
1 6408 8000
1 11822 16373
1 18716 23389
1 27690 34330
1 36552 39191
1 39313 44565
2 44839 50247
2 60987 65017
2 65705 71523
我的目标是选择文件中的行D bpos
文件中的where 字段测试落在范围内开始和停止文件的D b。有一个限制,即比赛必须在规定时间内进行卡托团体。这两个文件均按字段 1 和 2 排序。顺便说一句,我的两个真实文件还有许多其他字段。
对于这个示例数据集,我的预期结果是:
1 6408 8000
2 44839 50247
我有一个我已经混合好的脚本。
k=1;
data_test=$(cat "test")
data_db=$(cat "db")
while read -r line
do
# helps to keep count of test rows
printf "$k \n"
# get cato
cato=$(echo $line | awk '{print $1}')
# get pos
pos=$(echo $line | awk '{print $2}')
# get number of chars in pos (to reduce number of lines awk needs to look through later)
pos_chr=$(echo -n $pos | wc -c)
# get lines in db that start with cato and pos chars match start or stop
matched=$(echo "$data_db" | grep -Ew "^$cato" | grep -Ew "[0-9]{$pos_chr}")
#echo "$db_cat"
# if matched is not empty
if [ ! -z "$matched" ]; then
# use awk to print lines in db where pos > start and pos < stop
echo "$matched" | awk -v apos='$pos' 'BEGIN{OFS="\t"}{if(apos >= $2 && apos <= $3) print $0}'
#check
#echo "$matched" | awk -v apos=$pos 'BEGIN{OFS="\t"}{print apos,$0}'
fi
((k=k+1))
done <<< "$data_test"
好像awk
最后一步没有做比较。事情似乎一直进行到最后一步,然后我不确定出了什么问题。也许有人看到了错误。有一个更好的方法吗?
答案1
使用单一 GNUawk
程序(自Gawk
v4.0 起):
awk 'NR==FNR{ a[$1][$2]; next }
$1 in a{
for (i in a[$1])
if (i >= $2 && i <= $3) { print $0; break }
}' test db
输出:
1 6408 8000
2 44839 50247
答案2
使用join
简单的test
:
$ cat is-between.sh
#!/bin/bash
while read cato start stop pos; do
[ $start -le $pos -a $pos -le $stop ] && echo "$cato $start $stop"
done < <(join db test)
$ ./is-between.sh
1 6408 8000
2 44839 50247
您拥有关系数据:一个文件中的键值与另一个文件中的键值逐行匹配。join
是将这些结合在一起的工具。运行,您会发现它与数据在数据库中的join db test
结果相同。SELECT * FROM db JOIN test on test.cato=db.cato
有了这个,您现在就拥有了将起点、终点和位置放在一行上的行。循环这些,使用 atest
检查范围,就很容易了。