grep에서 욕심없는 매치를하는 방법?


답변:


276

당신은 욕심이없는 (또는 게으른) 성냥을 찾고 있습니다. 정규 표현식에서 욕심없는 일치를 얻으려면 ?수량화 후 수정자를 사용해야합니다 . 예를 들어, 당신은 변경할 수 있습니다 .*.*?.

기본적 grep으로 욕심없는 수정자를 지원하지 않지만 grep -PPerl 구문을 사용하는 데 사용할 수 있습니다 .


3
eegg : dot all 한정자를 멀티 라인이라고도합니다. "."를 변경하는 수정 자입니다. 줄 바꿈을 포함하도록 동작을 일치시킵니다 (일반적으로 그렇지 않습니다). grep에는 그러한 수정자가 없지만 pcregrep에는 있습니다.
A. Wilson

1
정정 :이를 지원하는 대부분의 정규 표현식 .에서 개행을 일치 시키는 모드를 DOTALL 또는 단일 라인 모드 라고 합니다. 루비는 멀티 라인 이라고하는 유일한 제품 입니다. 다른 특징에서, 멀티 라인 은 앵커 ( ^$)를 선 경계에서 일치 시킬 수있는 모드입니다 . 루비에서는 항상 그런 식으로 작동하기 때문에 루비에는 동등한 모드가 없습니다.
Alan Moore

5
-P나에게 완전한 새로운 것이었고, 나는 행복하게 몇 년 동안 쫓아 -E왔습니다. -자기 자신에 대한 참고 사항 : 매뉴얼 페이지를 (더 많은!) 규칙적인 것으로 다시 읽으십시오. 스위치와 옵션을 충분히 요약하지 마십시오.
ocodo

29
(맥 OS X가 같은) 어떤 플랫폼에서 grep지원하지 않습니다 -P,하지만 당신이 사용하는 경우 egrep에는 사용할 수있는 .*?동일한 결과를 달성하기 위해 패턴을. egrep -o 'start.*?end' text.html
SaltyNuts

4
@SaltyNuts 주석의 확장으로, 맥 OS X는 지원하지 않습니다 -P-E부를 것이다 egrep, 따라서 제안 된 .*?잘 작동합니다.
Fredrik Erlandsson '12

83

실제로 .*?유일하게 작동합니다 perl. 동등한 grep 확장 regexp 구문이 무엇인지 잘 모르겠습니다. 다행히도 grep과 함께 perl 구문을 사용할 수 있으므로 grep -P작동하지만 작동하지 않는 grep -E것과 동일 egrep합니다 (욕심이 많음).

참조 : http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html


9
grep -P바로 자동으로 적용되지 않습니다 (이 오류가 나던 바로 그것을 시도 - GNU에없는 일이 2.9 grep을 않습니다 ?Intertestly 어느 쪽도하지 않습니다. 클래스가 아닌 예는 :env|grep '[^\=]*\='
로베르토 토마스

2
Darwin / OS X 10.8 Mountain Lion 에는 grep -P옵션이나 pgrep명령이 없지만 egrep훌륭하게 작동합니다.
Steve HHH

2
거기의 pgrep내 OS X 10.9 상자에 명령하지만, 그 목적은 "이름으로 찾기 또는 신호 프로세스"에있는 완전히 다른 프로그램입니다.
Desty

@ robertotomás 6 살짜리 코멘트에 응답하지만, .... 나는 이것을 생각하고 여러 개의 욕심없는 일치를 얻고 있음을 깨달았습니다. 예를 들어, 컬러 터미널에서`echo "bbbbb"| grep -P 'b. *? b'`는 2 개의 일치 항목을 반환합니다.
zzxyz 2018

12

이 스레드에서 물건을 시험해 본 후에 작동하는 내 grep :

echo "hi how are you " | grep -shoP ".*? "

각 줄에 공백을 추가하십시오.

(마인은 한 줄씩 검색하여 단어를 뱉어 냈습니다)


3
-shoPnice mnemonic :)
Mariusz

echo "bbbbb" | grep -shoP 'b.*?b'약간의 학습 경험입니다. 명시 적으로 게으른 측면에서 나를 위해 일한 것 만.
zzxyz 2018

12

grep

욕심없는 일치의 grep경우 부정 문자 클래스를 사용할 수 있습니다. 즉, 와일드 카드를 피하십시오.

예를 들어, 페이지 컨텐츠에서 jpeg 파일에 대한 모든 링크를 가져 오려면 다음을 사용하십시오.

grep -o '"[^" ]\+.jpg"'

여러 줄을 처리하려면 xargs먼저 입력을 파이프로 연결하십시오 . 성능을 위해을 사용하십시오 ripgrep.


3

짧은 대답은 다음 정규식을 사용하는 것입니다.

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s)-여러 줄에 걸쳐 일치합니다.
  • . *? -게으른 방식으로 모든 문자와 일치합니다 (최소 일치)

좀 더 복잡한 대답은 다음과 같습니다.

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

다음 텍스트에서 car1과 car2를 일치시킬 수 있습니다.

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..)는 캡처 그룹을 나타냅니다
  • 이 문맥에서 \ 1은 그룹 번호 1을 캡처하여 가장 최근에 일치 한 것과 동일한 텍스트와 일치합니다.

1

늦어서 죄송합니다. 2020 년에는 시청자에게 효과가있을 수 있습니다.

따라서 같은 줄이 있다고 가정하십시오 "Hello my name is Jello". 이제 사이에 임의의 수의 문자가있는로 시작 'H'하고 끝나는 단어를 찾으려고합니다 'o'. 그리고 우리는 단어 만 원하는 줄을 원하지 않습니다. 이를 위해 다음 표현식을 사용할 수 있습니다.

grep "H[^ ]*o" file

이것은 모든 단어를 반환합니다. 이것이 작동하는 방식은 다음과 같습니다. 공백 문자 대신 모든 문자를 허용하므로 같은 줄에서 여러 단어를 피할 수 있습니다.

이제 공백 문자를 원하는 다른 문자로 바꿀 수 있습니다. 초기 줄이라고 가정하면 "Hello-my-name-is-Jello"표현식을 사용하여 단어를 얻을 수 있습니다.

grep "H[^-]*o" file

0

나는 그 게시물이 약간 죽은 것을 알고 있지만 이것이 효과가 있음을 알았습니다. 출력에서 정리와 정리를 모두 제거했습니다.

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.