Grep은 파일의 단어 단락과 일치합니다.

Grep은 파일의 단어 단락과 일치합니다.

단락으로 구성된 파일( )이 있습니다 myfile. 즉, 항목이 빈 줄로 구분됩니다. 를 기반으로 이러한 단락 중 일부를 검색하고 싶습니다 match.

이제 게임이 하나뿐이면 모든 것이 재미있고 게임이 됩니다. 저는 그냥 이렇게 합니다 awk -v RS='' '/match/ {print}' myfile.여기. 문제는 에서 수백 개의 일치 항목을 찾았는데 file이를 다른 파일( )에 수집했다는 것 입니다 matchfile. 일치하는 행만 검색해야 한다면 grep -f matchfile myfile.

grep -f전체 단락을 검색하는 것과 같은 작업을 수행할 수 있는 방법이 있습니까 ? 내 취향의 Unix에서는 이를 지원하지 않습니다 grep -p.

답변1

단락을 한 줄로 바꾸고 grep -f matchfile결과를 사용한 다음 줄 바꿈을 복원할 수 있습니다.

sed '/^$/s/^/\x02/' myfile | tr \\n$'\002' $'\003'\\n \
| grep -f matchfile |  tr $'\003' \\n | head -n -1

head출력에 뒤에 오는 빈 줄이 문제가 되지 않으면 생략할 수 있습니다.
따라서... 각 빈 줄의 시작 부분에 sed추가한 다음 모든 줄 바꿈을 줄 바꿈 으로 변환합니다 (원래 줄이 일부 낮은 ASCII 문자로 구분된 필드인 단일 줄로 효과적으로 모든 단락을 변환합니다. 이는 텍스트 파일에서는 발생하지 않습니다). - 이 경우 ) 일치하는 항목만 선택합니다.\x02tr\x03\x02\x03grep"철사";마지막으로 두 번째는 tr개행을 복원하고 head뒤에 오는 빈 줄을 삭제합니다(예를 들어 다른 도구를 사용할 수 있습니다 sed \$d).
실제로 작동 방식을 이해하는 가장 쉬운 방법은 단계적으로 실행하는 것입니다. 첫 번째 명령을 실행한 다음 첫 번째 및 두 번째 명령 등을 실행하고 출력을 살펴보세요. 설명이 필요합니다 1 .


tr1: 매뉴얼을 읽고 익숙해졌다면...

답변2

자, 그렇게 빨리 포기하지 마세요 awk!

awk 'NR == FNR {
          aMatch[NR]=$0
          n=FNR
          next;
    }
    {
          RS="\n( |\t)*\n"
          for(i=1; i<n+1; i++) {
             if($0 ~ aMatch[i]) {
               print
               printf "\n"
               break                   
             }                 
          }
    }' matchFile myFile | head -n-1

그러나 이를 스크립트에 넣을 수도 있습니다.

awk -f myscript.awk matchFile myFile | head -n-1

awk수행 작업에 대한 설명이 포함된 스크립트 형식의 솔루션 :

# This block's instructions will only be executed for the first file (containing the lines to be matched)
# NR = number of line read, and FNR = number of line read in current file   
# So the predicate NR == FNR is only true when reading the first file !
NR == FNR {
   aMatch[NR]=$0          # Store the line to match in an array
   n=FNR                  # Store the number of matches
   next;                  # Tells awk to skip further instructions (they are intended for the other file) and process the next record
}
# We are now processing the second file (containing the paragraphs)
{
   RS="\n( |\t)*\n"          # Set record separator to a blank line. Instead of a single line, a record is now the entire paragraph
   for(i=1; i<n+1; i++) {    # Loop on all possible matches
      if($0 ~ aMatch[i]) {   # If $0 (the whole record i.e. paragraph) matches a line we read in file 1 then
         print               # Print the record (i.e. current paragraph)
         printf "\n"         # Print a new line to separate them. However we will end up with a trailing newline, hence the pipe to head -n-1 to get rid of it.
         break               # We need to break out of the loop otherwise paragraphs with n matches will be printed n times
      }                      # End of loop on matches
   }                         # End of 2nd file processing
}

답변3

이를 수행하는 것은 매우 간단합니다.

awk -v RS="" -v ORS="\n\n" '/match/' myfile

관련 정보