语境
我是一名邮政工作人员(邮件分拣员),正在尝试编写一个 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 f
或107 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}
'
步骤:
- 检查数字是奇数还是偶数,并相应地准备排除字符串。
- 第一个
grep
选择与街道匹配的线路。所有行都匹配空字符串,因此不指定街道将使所有行在此步骤中匹配。 - 第二个
grep
步骤使用第一步中的排除字符串排除描述为“奇数”或“偶数”的条目。 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"