Bash

成功找到數字範圍時排除字元串。後續關於在房屋地址 txt 中搜尋字元串的先前問題

  • May 10, 2021

語境

這是我之前提出的問題的後續問題。在從Kamil MaciorowskiCyrus獲得一些驚人的幫助之前,我沒有意識到一個新的細節/問題。由於他的解釋和簡潔,我選擇了 Kamil Maciorowski 的答案,儘管這兩個答案都達到了我當時正在尋找的答案。我之前的問題中解釋了這個腳本的確切原因。

這是什麼

Kamil Maciorowski的程式碼,稱為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

在這裡,它返回範例 drNS,這對我來說很重要,也是我需要它的行為方式。

我有什麼問題

在我最初的問題中,我忽略了在我的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線。我希望它能夠返回 only 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,這與我的搜尋不匹配。

我試圖解決這個問題

Kamil Maciorowski暗示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]*$/)and(civic>=$1 && civic<=$2)行,它僅340-500 even sample rd S: ss11在搜尋時返回480 sam。然而一搜尋956 sam並沒有產生956 sample rd N: 53

我還嘗試在開頭添加另一個 if 排除script.sh,但我意識到單個門牌號碼並不像oddor一樣恆定even

任何進一步的幫助或建議將不勝感激。我知道當成功找到一個範圍時,我需要以某種方式排除單個門牌號碼,但我真的很難找到一種方法來解決這個問題。

此修改後的腳本添加了對單個數字的支持:

#! /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):

  1. 如果第一個欄位不完全是數字,那麼這意味著沒有範圍也沒有數字,並且行匹配。
  2. 否則,如果第二個欄位不完全是數字,則這意味著條目以單個數字開頭。在這種情況下,該行匹配當且僅當civic與數字匹配。
  3. 如果第一種情況和第二種情況都不是,則假設它是一個範圍。該行匹配當且僅當civic在該範圍內。

引用自:https://unix.stackexchange.com/questions/648977