"grep -zoP"를 통해 모든 경기를 개별적으로 표시하려면 어떻게해야합니까?

Nov 23 2020

이 양식에 파일이 있습니다.

X/this is the first match/blabla
X-this is
the second match-

and here we have some fluff.

그리고 "X"다음과 같은 마커 사이에 나타나는 모든 것을 추출하고 싶습니다. 따라서 "X + match +"가있는 경우 "X"뒤와 "+"마커 사이에 표시되므로 "일치"를 얻고 싶습니다.

따라서 주어진 샘플 파일에 대해 다음 출력을 원합니다.

this is the first match

그리고

this is
the second match

나는 다음을 사용하여 X와 마커 사이의 모든 내용을 얻을 수 있었다.

grep -zPo '(?<=X(.))(.|\n)+(?=\1)' file

그건:

  • grep -Po '(?<=X(.))(.|\n)+(?=\1)'X를 일치시키고 (something)그 다음에 캡처되고 끝에 일치합니다 (?=\1)( 여기 에 내 대답 에 대한 코드를 기반으로 함 ).
  • (.|\n)새 줄을 포함하여 모든 항목을 일치시키는 데 사용 하고 새 줄 -z을 일치시키기 위해 grep 에서도 사용 합니다.

따라서 이것은 잘 작동하며 유일한 문제는 출력 표시에서 발생합니다.

$ grep -zPo '(?<=X(.))(.|\n)+(?=\1)' file
this is the first matchthis is
the second match

보시다시피 모든 일치 항목이 함께 표시되며 "이것은 첫 번째 일치 항목입니다"뒤에 구분 기호없이 "이 항목이 두 번째 일치 항목입니다"가 표시됩니다. 모든 파일 을 줄 바꿈 ( "man grep"인용 ) 대신 0 바이트 (ASCII NUL 문자)로 끝나는 줄 집합으로 처리하는 "-z"사용에서 비롯된 것입니다 .

따라서이 모든 결과를 개별적으로 얻을 수있는 방법이 있습니까?

GNU Awk에서도 시도했습니다.

awk 'match($0, /X(.)(\n|.*)\1/, a) {print a[1]}' file

하지만 (\n|.*)일한 것 조차 아닙니다 .

답변

2 tripleee Nov 23 2020 at 20:23

사용 사례는 문제가됩니다. 일치 항목을 인쇄하자마자 구분 기호가 정확히 어디에 있는지에 대한 정보를 잃기 때문입니다. 하지만 허용되는 경우 xargs -r0.

grep -zPo '(?<=X(.))(.|\n)+(?=\1)' file | xargs -r0

이 옵션은 GNU 확장이지만 grep -z(대부분) grep -P그렇습니다. 그래서 아마도 그것은 받아 들일 수 있습니다.

5 Sundeep Nov 23 2020 at 20:16

awk regexp 정의 내에서 역 참조를 지원하지 않습니다.

해결 방법 :

$ grep -zPo '(?s)(?<=X(.)).+(?=\1)' ip.txt | tr '\0' '\n' this is the first match this is the second match # with ripgrep, which supports multiline matching $ rg -NoUP '(?s)(?<=X(.)).+(?=\1)' ip.txt
this is the first match
this is
the second match

(?s)X(.)\K.+(?=\1)대신 사용할 수도 있습니다 (?s)(?<=X(.)).+(?=\1). 또한 match+xyz+foobaz입력에 대한 일치를 피하기 위해 여기에 비 욕심 많은 수량자를 사용할 수 있습니다.X+match+xyz+foobaz+


perl

$ perl -0777 -nE 'say $& while(/X(.)\K.+(?=\1)/sg)' ip.txt
this is the first match
this is
the second match
4 anubhava Nov 23 2020 at 22:21

다음은 RS및 사용하는 또 다른 gnu-awk 솔루션입니다 RT.

awk -v RS='X.' 'ch != "" && n=index($0, ch) { print substr($0, 1, n-1)
}
RT {
   ch = substr(RT, 2, 1)
}' file
this is the first match
this is
the second match
3 EdMorton Nov 23 2020 at 21:51

다중 문자 RS, RT 및 gensub ()에 대해 GNU awk를 사용하고 전체 파일을 메모리로 읽을 필요가 없습니다.

$ awk -v RS='X.' 'NR>1{print "<" gensub(end".*","",1) ">"} {end=substr(RT,2,1)}' file
<this is the first match>
<this is
the second match>

분명히 "<"및 ">"를 추가하여 각 출력 레코드가 시작 / 종료되는 위치를 볼 수 있습니다.

위에서 문자 후에 그지지 X않은 반복 정규식 metachar (예 아닌 ., ^, [등) 때문에 YMMV

1 rowboat Nov 24 2020 at 10:09

GNU grep -z는 null 문자로 입력 / 출력 레코드를 종료합니다 (와 같은 다른 도구와 함께 유용함 sort -z). pcregrep은 다음을 수행하지 않습니다.

pcregrep -Mo2 '(?s)X(.)(.+?)\1' file

-onumber둘러보기 대신 사용됩니다. ?지연 수량자가 추가되었습니다 ( \1나중에 발생 하는 경우 ).