Bash:通过匹配数字范围来过滤行

Bash:通过匹配数字范围来过滤行

我有一个文件测试与字段:卡托, 和位置

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程序(自Gawkv4.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检查范围,就很容易了。

相关内容