Grep'de "takip edilmeyen" için normal ifade ilerleme


104

Arkasından Ui\.gelmeyen, Linehatta sadece mektubun geldiği tüm durumlar için grep yapmaya çalışıyorumL

Belirli bir dizenin tüm örneklerini bulmak için bir normal ifade yazmanın doğru yolu nedir?

Lookaheads kullanma

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


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

5
Hangi regex alt türleri - PCRE, ERE, BRE, grep, ed, sed, perl, python, Java, C, ...?
Jonathan Leffler

4
Bir kenara, "olay bulunamadı", geçmiş genişletme kullanımından gelir. Hiç kullanmazsanız geçmiş genişletmeyi kapatmak isteyebilir ve bazen etkileşimli komutlarınızda bir ünlem işareti kullanabilmek isteyebilirsiniz. set +o histexpandBash veya set +HYMMV'de.
üçlü

12
Ayrıca geçmiş genişleme sorunum vardı. Ben düşünüyorum ben sadece kabuk argüman gizleyin çalışmayın diye, tek tırnak geçerek onu çözdü.
Coderer

Sorunumu da çözen @Coderer. Teşekkürler.
NHDaly

Yanıtlar:


151

Negatif önden ilerleme, yani peşinde olduğunuz şey, standarttan daha güçlü bir araç gerektirir grep. PCRE uyumlu bir grep'e ihtiyacınız var.

GNU'nuz varsa grep, mevcut sürüm -Pveya seçeneklerini destekler --perl-regexpve ardından istediğiniz regex'i kullanabilirsiniz.

GNU'nun (yeterince yeni bir sürümüne) sahip değilseniz grep, edinmeyi düşünün ack.


37
Eminim ki bu durumda sorun sadece bash'de çift tırnak değil tek tırnak kullanmanız gerektiğidir, böylece !özel bir karakter olarak ele alınmaz .
NHDaly

(Tam olarak bunu açıklayan cevabım için aşağıya bakın.)
NHDaly

4
Doğrulanmış, doğru yanıt, bu yanıtı ve @ NHDaly'nin yorumunu birleştirmelidir. Örneğin, bu komut benim için çalışıyor: grep -P '^. * İçerir ((?! But_not_this).) * $' * .Log. *> "D: \ temp \ result.out"
wangf

3
Bilinmeyenler için -Ptekrar deneyin boru sonucu desteklenmez grep --invert-match: eski erkek git log --diff-filter=D --summary | grep -E 'delete.*? src' | grep -E --invert-match 'xml'. @Vinicius Ottoni'nin cevabına olumlu oy verdiğinizden emin olun.
Daniel Sokolowski

@wangf Cygwin altında Bash kullanıyorum ve tek tırnaklarla değiştirdiğimde, hala "olay bulunamadı" hatasını alıyorum.
SSilk

41

Probleminizin bir kısmının cevabı buradadır ve ack de aynı şekilde davranacaktır: Ack ve negatif bakış açısı hataları veriyor

Grep için, bash'nin " !geçmiş genişletme komutu olarak yorumlamasına" izin veren çift tırnak kullanıyorsunuz .

Deseninizi TEK TEKLİFLERLE sarmalamanız gerekiyor: grep 'Ui\.(?!L)' *

Ancak bkz. standart olarak olumsuz ön yüzlerle ilgili sorunları çözmek için @ JonathanLeffler'in cevabınagrep !


GNU'nun uzantı işlevselliğini , standardın POSIX olduğu grepstandart işleviyle karıştırıyorsunuz . Söylediğiniz şey de doğru - Bash'i C kabuğu barbarlıkları devre dışı bırakılmış olarak çalıştırıyorum (çünkü eğer bir C kabuğu isteseydim, birini kullanırdım ama istemiyorum), bu yüzden şeyler beni etkilemez - ancak negatif bakış açıları elde etmek için standart olmayana ihtiyacınız var . grepgrep!grep
Jonathan Leffler

1
@JonathanLeffler, açıklama için teşekkürler; Bence OP'nin tüm semptomlarını ele almak için her iki cevabımızı da gerektirdiği konusunda haklısınız. Teşekkürler.
NHDaly

11

Muhtemelen grep kullanarak standart negatif önden okuma yapamazsınız, ancak genellikle "ters" anahtarı '-v' kullanarak eşdeğer davranış elde edebilmelisiniz. Bunu kullanarak, eşleştirmek istediğiniz şeyin tamamlayıcısı için bir normal ifade oluşturabilir ve ardından onu 2 gruptan geçirebilirsiniz.

Söz konusu normal ifade için şöyle bir şey yapabilirsiniz:

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

Bu, satırda .Line olmadan Ui.Line ve Ui içeriyorsa daha fazla şey hariç tutulur
nafg

1
(Evet, bu yüzden tam olarak formüle etmiyorum. Bu, insanları bu soruna götüren senaryoların önemli bir bölümünü çözüyor, başka bir şey değil.)
Karel Tucek

4

Negatif ön yüzleri desteklemeyen bir normal ifade uygulaması kullanmanız gerekiyorsa ve fazladan karakter (leri) * eşleştirmeyi önemsemiyorsanız, olumsuzlanmış karakter sınıflarını[^L] , alternatifi| ve dize bağlantısının sonunu kullanabilirsiniz.$ .

Senin durumunda grep 'Ui\.\([^L]\|$\)' *iş yapıyor.

  • Ui\. ilgilendiğiniz dizeyle eşleşir

  • \([^L]\|$\)dışında herhangi bir tek karakterle Leşleşir [^L]veya satırın sonuyla eşleşir: veya $.

Birden fazla karakteri dışlamak istiyorsanız, o zaman ona daha fazla alternatif ve olumsuzluk atmanız gerekir. aArdından gelmeyenleri bulmak için bc:

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

Hangi ya (edilir adeğil, ardından b: hattın sonuna kadar ya da ardından a, sonra [^b]ya $veya () ave ardından bya da hangi olmayan takip eder cya da hattın sonuna kadar takip edilir: adaha sonra b, o zaman [^c]ya da $.

Bu tür bir ifade, oldukça hantal ve kısa bir dizeyle bile hataya açık hale gelir. İfadeleri sizin için oluşturmak için bir şeyler yazabilirsiniz, ancak muhtemelen negatif ön yüzleri destekleyen bir normal ifade uygulaması kullanmak daha kolay olacaktır.

* Uygulamanız yakalama yapmayan grupları destekliyorsa , fazladan karakterleri yakalamaktan kaçınabilirsiniz.


1

Grep'iniz -P veya --perl-regexp'i desteklemiyorsa ve PCRE'nin etkin olduğu grep'i yükleyebilirsiniz, örneğin "pcregrep", Perl uyumlu normali kabul etmek için GNU grep gibi komut satırı seçeneklerine ihtiyaç duymayacaktır. ifadeler, sadece koşuyorsun

pcregrep "Ui\.(?!Line)"

Örneğin "Ui. (?! (Çizgi))" örneğinizdeki gibi "Çizgi" için başka bir iç içe gruba ihtiyacınız yoktur - yukarıda gösterdiğim gibi dış grup yeterlidir.

Negatif iddialara bakmanın başka bir örneğini vereyim: "ipset" ile döndürülen satırların listesine sahip olduğunuzda, her satır satırın ortasındaki paket sayısını gösterir ve sıfır paketli satırlara ihtiyacınız yoksa, yalnızca Çalıştırmak:

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

Perl uyumlu normal ifadeleri seviyorsanız ve perl'e sahipseniz ancak pcregrep'e sahip değilseniz veya grep'iniz --perl-regexp'i desteklemiyorsa, grep gibi aynı şekilde çalışan tek satırlık perl komut dosyalarını kullanabilirsiniz:

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

Perl, stdin'i grep gibi aynı şekilde kabul eder, ör.

ipset list | perl -e "while (<>) {if (/packets(?! 0 )/){print;};}"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.