使用 shell 脚本检查另一个文件中的数字是否在范围内

Check number in another file if in range using shell script

我有两个文件(fileA 和 fileB)。 FileA 包含数字列表,fileB 包含数字范围。

文件A

  446646452
  000000001
  63495980020

fileB(range_from 和 range_to)

  22400208, 22400208
  446646450,    446646450
  63495980000,  63495989999

输出必须是

  63495980020

在sql脚本中就像

 select *
 from fileB
 where 446646452 between Range_from and Range_To

如何使用 shell 脚本来完成?

打印匹配任何范围的数字

$ awk 'FNR==NR{low[NR]=+0; hi[NR]=+0;next} {for (i in low)if (>low[i] && <hi[i]){print ;next}}' fileB fileA
63495980020

工作原理

  • FNR==NR{low[NR]=+0; hi[NR]=+0;next}

    读取第一个文件时,fileB,将范围的低端保存在数组 low 中,将范围的高端保存在数组 hi.

  • for (i in low)if (>low[i] && <hi[i]){print ;next}

    读取第二个文件时,fileA,检查每个范围内的数字。如果它满足任何范围,则打印它并跳到 next 行。

打印符合各自范围的数字

$ paste fileA fileB | awk '>+0 && <+0{print }'
63495980020

注意只打印了63495980020。 446646452不在22400208和22400208之间,所以省略

工作原理

实用程序 paste 组合文件如下:

$ paste fileA fileB 
  446646452       22400208, 22400208
  000000001       446646450,    446646450
  63495980020     63495980000,  63495989999

第一列是我们感兴趣的数字,第二列是范围的低值,第三列是高值。我们要打印第一个值 </code>,如果它介于第二个和第三个之间。要测试它是否大于第二个,我们可以尝试:</p> <pre><code>>

但是,为了确保 awk 将字段视为数字而不是字符串,我们对其中一个数字执行加法,如下所示:

>+0

同理,判断第一个数是否小于第三个数:

<+0

将这两个测试与打印命令放在一起产生:

>+0 && <+0 {print }

此测试严格介于之间。根据您的要求,您可能更喜欢:

>=+0 && <=+0 {print }

根据 OP 的说明,fileA 中的每个值都应根据 fileB 中的 所有 范围进行检查,以查看它是否属于 至少一个范围。
假定范围检查的 >=<= 逻辑(即包括与范围端点一致的值)。

awk -F', +' '
  # 1st pass (fileB): read the lower and upper range bounds
 FNR==NR { lbs[++count] = +0; ubs[count] = +0; next }
  # 2nd pass (fileA): check each line against all ranges.
 { 
   for(i=1;i<=count;++i) {
    if (+0 >= lbs[i] && +0 <= ubs[i]) { print; next }
   }
 }
' fileB fileA
  • awk 用于读取两个文件,使用单独的通道:
    • FNR==NR 对来自 fileB 的所有行都成立;构建范围的下限 (lbs) 和上限 (ubs) 的并行数组;感谢 next,没有对 fileB 行应用进一步处理。
    • 随后的 {...} 块仅应用于来自 fileA.
    • 的行
    • 针对所有范围检查 fileA 中的每个值,一旦找到匹配项,就会打印输入行并继续处理下一行。
    • 为了确保所有涉及的标记都被视为 数字+0 被添加到它们。

老式脚本

sed 's/,[[:space:]]*/ /' fileB \
 | while read LowVal HighVal
    do
      while read ThisLine
       do
         [ ${ThisLine} -ge ${LowVal} ] && [ ${ThisLine} -le ${HighVal} ] && echo "${ThisLine}"
       done < fileA
    done