정확한 번호와 거리 이름을 전달하여 다양한 숫자가 포함된 집 주소 텍스트 내에서 문자열을 찾습니다.

정확한 번호와 거리 이름을 전달하여 다양한 숫자가 포함된 집 주소 텍스트 내에서 문자열을 찾습니다.

문맥

저는 우편 직원(메일 분류기)이고 정확한 거리 주소와 거리 이름의 처음 몇 글자를 입력하고 경로 번호 정보 문자열이 포함된 일치하는 문자를 반환하도록 하는 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: 1698-258 even foo st N: 1521-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}
     '

단계:

  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"

관련 정보