단락으로 구성된 파일( )이 있습니다 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 문자로 구분된 필드인 단일 줄로 효과적으로 모든 단락을 변환합니다. 이는 텍스트 파일에서는 발생하지 않습니다). - 이 경우 ) 일치하는 항목만 선택합니다.\x02
tr
\x03
\x02
\x03
grep
"철사";마지막으로 두 번째는 tr
개행을 복원하고 head
뒤에 오는 빈 줄을 삭제합니다(예를 들어 다른 도구를 사용할 수 있습니다 sed \$d
).
실제로 작동 방식을 이해하는 가장 쉬운 방법은 단계적으로 실행하는 것입니다. 첫 번째 명령을 실행한 다음 첫 번째 및 두 번째 명령 등을 실행하고 출력을 살펴보세요. 설명이 필요합니다 1 .
tr
1: 매뉴얼을 읽고 익숙해졌다면...
답변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