grep에서 '뒤에없는'에 대한 정규식 미리보기


103

나는 Ui\.뒤 따르지 않는 모든 경우 Line또는 심지어 편지에 대해 grep을 시도하고 있습니다.L

다른 문자열이 뒤 따르지 않는 특정 문자열의 모든 인스턴스를 찾기 위해 정규식을 작성하는 적절한 방법은 무엇입니까?

미리보기 사용

grep "Ui\.(?!L)" *
bash: !L: event not found


grep "Ui\.(?!(Line))" *
nothing

5
정규식의 어떤 하위 종-PCRE, ERE, BRE, grep, ed, sed, perl, python, Java, C, ...?
Jonathan Leffler 2012

4
제쳐두고 "이벤트를 찾을 수 없음"은 히스토리 확장을 사용하여 발생합니다. 히스토리 확장을 사용하지 않는 경우 끄고 대화식 명령에 느낌표를 사용하려는 경우도 있습니다. set +o histexpandBash 또는 set +HYMMV에서.
tripleee 2012

12
역사 확장 문제도있었습니다. 나는 작은 따옴표로 바꾸는 것만으로 그것을 해결 했다고 생각 한다. 그래서 쉘은 논쟁을 방해하지 않을 것이다.
Coderer

내 문제도 해결 한 @Coderer. 감사.
NHDaly

답변:


151

당신이 추구하는 부정적 예측은 표준보다 더 강력한 도구가 필요합니다 grep. PCRE 사용 grep이 필요합니다.

GNU grep가있는 경우 현재 버전이 옵션을 지원 -P하거나 --perl-regexp원하는 정규식을 사용할 수 있습니다.

당신이 (충분히 최신 버전) GNU이없는 경우 grep, 다음 고려지고 ack.


37
이 경우 문제는 bash에서 큰 따옴표가 아닌 작은 따옴표를 사용해야하므로 !특수 문자로 처리되지 않는다는 것입니다 .
NHDaly

(정확히 설명하는 내 대답은 아래를 참조하십시오.)
NHDaly

4
확인 된 정답은이 답변과 @NHDaly의 의견을 결합해야합니다. 예를 들어 다음 명령은 저에게 적합합니다. grep -P '^. * contains ((?! but_not_this).) * $'* .log. *> "D : \ temp \ result.out"
wangf

3
여기서 사람들을 위해 -P다시 시도 배관 결과를 지원하지 않습니다 grep --invert-match: 예, git log --diff-filter=D --summary | grep -E 'delete.*? src' | grep -E --invert-match 'xml'. @Vinicius Ottoni의 답변에 찬성 투표하십시오.
Daniel Sokolowski 2011

@wangf Cygwin에서 Bash를 사용하고 있으며 작은 따옴표로 변경해도 "이벤트를 찾을 수 없음"이라는 오류가 계속 발생합니다.
SSilk 2017-06-23

40

문제의 일부에 대한 답은 여기에 있으며 ack는 동일한 방식으로 작동합니다. 오류를주는 Ack 및 부정적 예측

grep에 큰 따옴표를 사용하여 bash가 " !히스토리 확장 명령으로 해석"할 수 있도록 합니다.

패턴을 단일 따옴표로 감싸 야합니다. grep 'Ui\.(?!L)' *

그러나 표준에서 부정적인 예견 문제를 해결하려면 @JonathanLeffler의 답변 을 참조하십시오 grep!


GNU의 확장 기능 grep을 표준 기능과 혼동하고 있습니다 grep. 여기서 표준 grep은 POSIX입니다. 당신이 말을하는 것은 사실이다 - 그렇게, 나는 비활성화 C 쉘 barbarisms으로 배쉬를 실행 (나는 C 쉘을 원한다면, 내가 하나를 사용 것 때문에,하지만 난 하나를 원하지 않는) !물건이 나에게 영향을주지 않습니다 - 그러나 부정적인 예측을 얻으려면 비표준이 필요합니다 grep.
Jonathan Leffler

1
@JonathanLeffler, 설명에 감사드립니다. OP의 모든 증상을 해결하기 위해 두 가지 답변이 모두 필요하다는 것이 옳다고 생각합니다. 감사.
NHDaly

11

grep을 사용하여 표준 부정 예측을 수행 할 수는 없지만 일반적으로 "inverse"스위치 '-v'를 사용하여 동등한 동작을 얻을 수 있습니다. 이를 사용하여 일치하려는 항목의 보완을위한 정규식을 구성한 다음 2 개의 greps를 통해 파이프 할 수 있습니다.

문제의 정규식의 경우 다음과 같이 할 수 있습니다.

grep 'Ui\.' * | grep -v 'Ui\.L'

하여 선 .Line없이 Ui.Line 및 UI가 포함되어있는 경우 그 가지 더, 더 인스턴스를 제외 것
nafg

1
(예, 이것이
제가

4

네거티브 룩어 헤드를 지원하지 않는 정규식 구현을 사용해야하고 추가 문자 * 일치에 신경 쓰지 않는다면 부정 문자 클래스[^L] , alternation|문자열 anchor$끝을 사용할 수 있습니다 .

귀하의 경우 grep 'Ui\.\([^L]\|$\)' *에는 일을합니다.

  • Ui\. 관심있는 문자열과 일치합니다.

  • \([^L]\|$\)다른 단일 문자 L와 일치 [^L]하거나 줄의 끝과 일치합니다 : 또는 $.

둘 이상의 캐릭터를 제외하려면 더 많은 교대와 부정을 던져야합니다. a뒤 따르지 않는 것을 찾으려면 bc:

grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *

다음 중 하나는 ( a뒤에 not b또는 그 뒤에 줄 끝 : athen [^b]또는 $) 또는 ( a뒤에 bnot c뒤에 있거나 줄의 끝 : athen b, then [^c]또는 $.

이런 종류의 표현은 매우 다루기 어렵고 짧은 문자열로도 오류가 발생하기 쉽습니다. 표현식을 생성하기 위해 무언가를 작성할 수 있지만 부정적인 예측을 지원하는 정규식 구현을 사용하는 것이 더 쉬울 것입니다.

* 구현이 비 캡처 그룹 을 지원하는 경우 추가 문자 캡처를 피할 수 있습니다.


1

grep이 -P 또는 --perl-regexp를 지원하지 않고 PCRE 사용 grep (예 : "pcregrep")을 설치할 수있는 경우 Perl 호환 일반을 허용하기 위해 GNU grep과 같은 명령 줄 옵션이 필요하지 않습니다. 식, 당신은 그냥 실행

pcregrep "Ui\.(?!Line)"

"Ui. (?! (Line))"예제에서와 같이 "Line"에 대해 다른 중첩 그룹이 필요하지 않습니다. 위에 표시된 것처럼 외부 그룹이면 충분합니다.

부정적인 어설 션을 보는 또 다른 예를 들겠습니다. "ipset"에 의해 반환 된 라인 목록이 있고 라인 중간에 패킷 수를 표시하는 각 라인이 있고 패킷이없는 라인이 필요하지 않은 경우 운영:

ipset list | pcregrep "packets(?! 0 )"

perl 호환 정규식을 좋아하고 perl이 있지만 pcregrep이 없거나 grep이 --perl-regexp를 지원하지 않는 경우 grep과 같은 방식으로 작동하는 한 줄짜리 perl 스크립트를 사용할 수 있습니다.

perl -e "while (<>) {if (/Ui\.(?!Lines)/){print;};}"

Perl은 grep과 같은 방식으로 stdin을 허용합니다.

ipset list | perl -e "while (<>) {if (/packets(?! 0 )/){print;};}"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.