コンテキスト
私は郵便の従業員(メール分類器)で、正確な通りの住所と通りの名前の最初の数文字を入力し、パス番号情報文字列を含む一致する文字を返す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が7757から8079の範囲にあるので、8020 h
入力して戻り続ける方法を探しています。7757-8079 hwy 9: ss14
また、foo stにはNとSのインジケータだけでなく、さまざまなパスの偶数と奇数の範囲があることをテキストで参照してください。家番号が変で帰る必要なく入ったり107 f
戻っ107 foo
たりする方法を探しています。これらの偶数/奇数の場合、単語の偶数/奇数は常に文字列に割り当てられているため、入力された家の番号が奇数の場合はgrepを使用するか、数値範囲内の文字列からこれらの単語を検索できますか?この例では、家の番号が範囲内にあり、文字列に奇数があるため(foo st Sを参照)も返されます。 NやSを指定する時間がないため、NとSを返すことに同意します。97-257 odd foo st N: 16
98-258 even foo st N: 15
21-301 odd foo st S: 17
完全な答えであれ、より詳細なヒントであれ、私の努力にご協力いただきありがとうございます。問題を起こそうとしたのではなく、ただ助けを求めるだけです!より具体的に説明できれば教えてください。
答え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
距離に一致する線を選択します。すべての行は空の文字列と一致するため、距離を指定しないと、このステップですべての行が一致します。 - 2番目
grep
のステップでは、最初のステップの除外文字列を使用して、「奇数」または「偶数」と記載されている項目を除外します。 awk
スペースを区切り文字として使用して、各行を分割します-
。最初の 2 つのフィールドのいずれかが正確に数値でない場合、範囲は指定されず、行が印刷されます。それ以外の場合は、明らかに最初の2つのフィールドが範囲を定義します。その後、数値が範囲に対してテストされ、範囲内にある場合、行が印刷されます。
答え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"