通过传入确切的号码和街道名称,在包含数字范围的房屋地址文本中查找字符串

通过传入确切的号码和街道名称,在包含数字范围的房屋地址文本中查找字符串

语境

我是一名邮政工作人员(邮件分拣员),正在尝试编写一个 bash 脚本,该脚本允许我输入准确的街道地址和街道名称的前几个字母,并让它返回包含路线号码信息的匹配字符串。我每天必须对数千封无法加工的信件进行分类,方法是低头查看信件,然后抬头查看印有我所在城市的每个地址的巨大海报。这个脚本可以节省我的时间,所以我正在尽最大努力学习完成它的过程。我对 UNIX/Linux 脚本编写有类似的爱好。不确定正则表达式是这里的解决方案,还是 grep、find、awk、sed 或所有这些的变体!

我有一个文本文件,其中包含地址列表(门牌号范围和街道名称),每个地址都在换行符上,如下所示:

6974-7075 hwy 99: ss1
7757-8079 hwy 99: ss14
98-258 even foo st N: 15
97-257 odd foo st N: 16
21-301 foo st S: 17
15-20 foo st S: 7
bar st: 1
fake st: 31
fake pl: 77
sample dr: 89

注意数字范围的存在、一条路线的街道(没有给出房屋编号)、偶数和奇数说明符、道路类型(st、hwy、pl、dr 等)、北(N)和南(S)指示符,最后是冒号后的路线信息。

当前状态

我有以下脚本,只要输入与文本文件中完全相同的街道号码,就可以返回我想要的字符串:

#! /bin/bash

civic="$1"
street="$2"

grep $civic.*$street /path/to/addresses.txt 

执行./script.sh 7757./script.sh 7757 h将返回7757-8079 hwy 99: ss14给我。我喜欢这里返回的完整字符串,而不仅仅是冒号之后的路线。但是,显然,执行./script.sh 8020 h不会返回7757-8079 hwy 99: ss14,因为我的代码尚未检查范围内的数字。

需要帮助

但是,我正在寻找一种能够输入8020 h并仍然返回的方法7757-8079 hwy 9: ss14,因为 8020 在 7757-8079 范围内。

此外,请注意文本中的 foo st 有不同路线的偶数和奇数范围,以及 N 和 S 指示符。我正在寻找一种能够进入107 f107 foo返回的方法97-257 odd foo st N: 16,而不需要返回98-258 even foo st N: 15,因为房子#很奇怪。对于这些偶数/奇数情况,单词偶数/奇数将始终在字符串中指定,因此如果输入的房屋 # 是奇数,则可能会在具有数字范围的字符串中使用 grep 或搜索这些单词?该示例也会返回21-301 odd foo st S: 17(注意 foo st S),因为 house # 在范围内,并且字符串中有奇数。我同意返回 N 和 S,因为我没有时间指定 N 或 S。

我将非常感谢在我的努力中提供的任何帮助,无论是完整的答案,还是更接近的暗示。不是来捣乱的,只是寻求帮助!如果我可以更具体的话请告诉我。

答案1

#! /bin/bash

civic="$1"
street="$2"

if [ "$((civic%2))" = 1 ]; then
   exclude=" even "
else
   exclude=" odd "
fi

</path/to/addresses.txt grep "$street" \
   | grep -v "$exclude" \
   | awk -F '[ -]' -v civic="$civic" '
      {if ($1 !~ /^[0123456789]*$/ || $2 !~ /^[0123456789]*$/) print
       else if (civic>=$1 && civic<=$2) print}
     '

步骤:

  1. 检查数字是奇数还是偶数,并相应地准备排除字符串。
  2. 第一个grep选择与街道匹配的线路。所有行都匹配空字符串,因此不指定街道将使所有行在此步骤中匹配。
  3. 第二个grep步骤使用第一步中的排除字符串排除描述为“奇数”或“偶数”的条目。
  4. awk分割每一行,使用空格-作为分隔符。如果前两个字段中的任何一个不完全是数字,则不指定范围并打印该行。否则显然前两个字段定义了一个范围;然后根据范围测试该数字,如果在该范围内则打印该行。

答案2

带有awk和一个bash包装纸。将其另存为script.sh并使其可执行。

#!/bin/bash

filename="data.txt"

n="$1"       # save number from argument list
shift        # remove number from argument list
s="$@"       # save remaining argument list
s="${s:=.*}" # set regex .* as default if street is missing

awk -v number="$n" -v street="$s" '
BEGIN{
  FS="-| "   # use field separator "-" or one space to split current row
}

$0 ~ street{
  # current row contains street

  if( $1 ~ /^[0-9]+$/ && $2 ~ /^[0-9]+$/ ){
    # current row starts with a range

    if( number >= $1 && number <= $2 ){
      # number is in expected range

      if ( $3 == "odd" || $3 == "even" ){
        # string "even" or "odd" found

        if ( $3 == "odd" && number ~ /[13579]$/ ){
          # odd
          print
        }

        if ( $3 == "even" && number ~ /[24680]$/ ){
          # even
          print
        }
      } else {
        # neither "even" or "odd" found
        print
      }
    }
    # finished with current row
    next
  }
  # match but no range found in current row
  print
}
' "$filename"

相关内容