语境
这是一个后续问题我之前问过的一个问题。在获得一些惊人的帮助之前,出现了一个我不知道的新细节/问题卡米尔·马乔罗夫斯基和赛勒斯。由于他的解释和简洁,我选择了卡米尔·马乔罗夫斯基的答案,尽管这两个答案都达到了我当时所寻求的目的。这个脚本的确切原因已在我之前的问题中解释过。
这是什么
卡米尔·马乔罗夫斯基的代码,称为script.sh
:
#! /bin/bash
civic="$1"
street="$2"
if [ "$((civic%2))" = 1 ]; then
exclude=" even "
else
exclude=" odd "
fi
</path/to/addresses.txt grep -E "(^| )$street" \
| grep -v "$exclude" \
| awk -F '[ -]' -v civic="$civic" '
{if ($1 !~ /^[0123456789]*$/ || $2 !~ /^[0123456789]*$/) print
else if (civic>=$1 && civic<=$2) print}
'
该代码允许我传递门牌号码和街道名称。它将addresses.txt
通过检查地址范围以及街道名称前面没有任何门牌号的地址来搜索并返回正确的字符串。以下是addresses.txt
演示变异案例的示例(匿名):
1 fastest rd S: 99
2-58 fastest rd N: 98
42 fake st: ss12
1 test st: 1
2-199 test st: 2
200-300 even test st: 22
301-399 odd test st: 33
example dr N: ss5
example dr S: 226
956 sample rd N: 53
976-998 even sample rd N: 54
340-500 even sample rd S: ss11
401-487 odd sample rd S: 45
使用该数据,我可以运行./script.sh 1 fas
并获得以下输出,这是完美的:
1 fastest rd s: 99
另一个完美的例子./script.sh 42 fak
:
42 fake st: ss12
另一个很好的例子./script.sh 20 ex
:
example dr N: ss5
example dr S: 226
这里它返回示例 drN
和S
,这对我来说很重要,并且是我需要它的行为方式。
我遇到了什么问题
在我最初的问题中,我忽略了在addresses.txt
样本中包含只有一个门牌号的字符串,而不是一个范围(例如1 test st: 1
:)。为了设置这部分的数据,以下是我上面addresses.txt
示例中的一些相关字符串:
1 fastest rd S: 99
2-58 fastest rd N: 98
1 test st: 1
2-199 test st: 2
956 sample rd N: 53
976-998 even sample rd N: 54
340-500 even sample rd S: ss11
401-487 odd sample rd S: 45
在脚本的当前状态(它是什么)下,运行./script.sh 89 tes
输出:
1 test st: 1
2-199 test st: 2
注意这1 test st: 1
条线。我希望它只能返回,因为这更2-199 test st: 2
符合我的搜索。89 tes
另一个例子,./script.sh 483 sam
:
956 sample rd N: 53
401-487 odd sample rd S: 45
请注意,它成功地将 483 识别为奇数,并将其与401-487 odd sample rd S: 45
范围匹配,而不是还包括340-500 even sample rd S: ss11
范围。但是,它也返回956 sample rd N: 53
,这与我的搜索不匹配。
我尝试解决这个问题
卡米尔·马乔罗夫斯基暗示awk
脚本的这一部分可以更改为“寻找第一个非完全数字字段,因此知道街道名称之前是否有范围、单个值或什么都没有”。我尝试添加另一else if
行,awk
尝试查找数字,如果房子 # 是单独的,则打印,后面跟一个空格。我补充道else if (civic =~ /^[0123456789]\s$/) print}
:
</path/to/addresses.txt grep -E "(^| )$street" \
| grep -v "$exclude" \
| awk -F '[ -]' -v civic="$civic" '
{if ($1 !~ /^[0123456789]*$/ || $2 !~ /^[0123456789]*$/) print
else if (civic>=$1 && civic<=$2) print
else if (civic =~ /^[0123456789]\s$/) print}
'
我并不完全感到惊讶,因为我无法阻止它抛出语法错误,因为这种表达式对我来说是新的。我尝试翻转($1 !~ /^[0123456789]*$/ || $2 !~ /^[0123456789]*$/)
和行,它们仅在搜索 时(civic>=$1 && civic<=$2)
返回。然而搜索并没有产生。340-500 even sample rd S: ss11
480 sam
956 sam
956 sample rd N: 53
我还尝试在 的开头添加另一个 if 排除script.sh
,但我意识到单个门牌号并不像odd
or那样恒定even
。
任何进一步的帮助或建议将不胜感激。我知道当成功找到范围时,我需要以某种方式排除单个门牌号,但我很难理解这样做的方法。
答案1
此修改后的脚本添加了对单个数字的支持:
#! /bin/bash
civic="$1"
street="$2"
if [ "$((civic%2))" = 1 ]; then
exclude=" even "
else
exclude=" odd "
fi
</path/to/addresses.txt grep -E "(^| )$street" \
| grep -v "$exclude" \
| awk -F '[ -]' -v civic="$civic" '
{if ($1 !~ /^[0123456789]*$/) print
else if ($2 !~ /^[0123456789]*$/) {if (civic==$1) print}
else if (civic>=$1 && civic<=$2) print}
'
该awk
代码现在考虑三种情况(记住过滤依据street
已经由 完成grep
;awk
过滤依据civic
):
- 如果第一个字段不完全是数字,则意味着没有范围或数字并且该行匹配。
- 否则,如果第二个字段不完全是数字,则意味着条目以单个数字开头。在这种情况下,当且仅当匹配
civic
数字,该行才匹配。 - 如果第一种情况和第二种情况都不是,则假设它是一个范围。该行匹配当且仅
civic
当在范围内。