grep, “Bar” ın 10 satırda görünmediği “Foo” örneklerini bulmak için


10

"Foo" nun oluştuğu tüm CPP dosyalarını tüm ağacında aramak istiyorum. Yapabilirim:

find . -name "*.cpp" | xargs grep "Foo"

Şimdi listeye istediğinizi varsayalım sadece diğer bazı dize, "Bar" söylüyorlar bu örnekleri değil önceki sonuca 3 çizgilerin içinde meydana gelir.

İki dosya verildi:

a.cpp

1 Foo
2 qwerty
3 qwerty

b.cpp

1 Foo
2 Bar
3 qwerty

Ben a.cpp "Foo" bulunduğu, ancak b.cpp "Foo" bulunmayan basit bir arama oluşturmak istiyorum.

Bunu oldukça basit bir şekilde başarmanın bir yolu var mı?


Belki çözelti, grep -A ve / veya grep -B ve / veya grep -C seçeneğinde olabilir. Deniyorum ama başarı yok ....
maurelio79

@ maurelio79: Mevcut teorim bu. Bağlam için -A 10 kullanarak "Foo" için Grep. Grep -v Bar boru. Dosya adını ve satır numarasını almak için bunu sed. Bu satırı yazdırmak için (bir şey?)
John Dibling

Yanıtlar:


17

İle pcregrep:

pcregrep --include='\.cpp$' -rnM 'Foo(?!(?:.*\n){0,2}.*Bar)' .

Anahtar, -Mbenzersiz pcregrepve birden çok satırı eşleştirmek için kullanılan seçenektir ( pcregrepRE istendiğinde gerektiğinde giriş dosyasından daha fazla veri alır).

(?!...)perl / PCRE negatif ileriye dönük RE operatörüdür. aşağıdakilerle eşleşmediği sürece Foo(?!...)eşleşir .Foo...

...olmak (?:.*\n){0,2}.*Bar( .ihtiva eden bir çizgi izlemektedir, 0 ila 2 hatları değil, bir yeni satır karakter eşleme olan) Bar.


+1: Mükemmel. Çok teşekkürler; Eminim doğru regex'i bulmak kolay değildi. Çabalarınızı çok takdir ediyorum. Bu tam istediğim gibi çalışıyor.
John Dibling

2
Yan soru cevaplamak istiyorsan. Nasıl bildin pcregrep? Daha önce hiç duymamıştım.
John Dibling

@JohnDibling, şahsen unix.SE'de öğrendim . RE, özellikle (?!...)negatif ileriye perldönük RE operatörü hakkında bilgi sahibi olduğunuzda özellikle karmaşık değildir .
Stéphane Chazelas

9

Aldırma, sadece kullanmak pcregrepolarak önerilen @StephaneChazelas tarafından.


Bu çalışmalı:

$ find . -name "*.cpp" | 
    while IFS= read -r file; do 
      grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; 
    done 

Fikir, -Aeşleşen satırları ve aşağıdaki N satırını çıkarmak için grep anahtarını kullanmaktır . Daha sonra sonucu birgrep Bar ve bu eşleşmezse (exit> 0), dosyanın adını yankılarsınız.

Aklı başında dosya adlarınız olduğunu (boşluk, yeni satır veya başka garip karakterler olmadığını) biliyorsanız, şunları basitleştirebilirsiniz:

$ for file in $(find . -name "*.cpp"); do 
   grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; 
  done 

Örneğin:

terdon@oregano foo $ cat a.cpp 
1 Foo
2 qwerty
3 qwerty
terdon@oregano foo $ cat b.cpp 
1 Foo
2 Bar
3 qwerty
terdon@oregano foo $ cat c.cpp 
1 Foo
2 qwerty
3 qwerty
4 qwerty
5. Bar
terdon@oregano foo $ for file in $(find . -name "*.cpp"); do grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; done 
./c.cpp
./a.cpp

İçerdiği çizgiye 3 satırdan fazla olduğu için c.cppiçermesine rağmen döndürüldüğünü unutmayın . Geçmek istediğiniz değeri değiştirerek aramak istediğiniz satır sayısını kontrol edersiniz :BarBarFoo-A

$ for file in $(find . -name "*.cpp"); do 
   grep -A 10 Foo "$file" | grep -q Bar || echo "$file"; 
  done 
./a.cpp

İşte daha kısa olanı (kullandığınız varsayılarak bash):

$ shopt -s globstar 
$ for file in **/*cpp; do 
    grep -A 10 Foo "$file" | grep -q Bar || echo "$file"; 
  done

ÖNEMLİ

Stephane Chazelas'ın yorumlarda belirttiği gibi, yukarıdaki çözümler de hiç içermeyen dosyalar basacaktır Foo. Bu bundan kaçınır:

for file in **/*cpp; do 
  grep -qm 1 Foo "$file" && 
  (grep -A 3 Foo "$file" | grep -q Bar || echo "$file"); 
done

+1 temiz-o. Umduğumdan biraz daha karmaşık, ama hiç de fena değil.
John Dibling

Bu, "Foo" nun yalnızca bir kez oluştuğunu varsayar. Bu, içermeyen dosyaları da rapor edecektir Foo. Alıntılarınız eksik.
Stéphane Chazelas

@ StephaneChazelas teşekkürler, tırnak düzeltildi. Hayır içeren dosyaları bildirme konusunda oldukça haklısınız Foove bunu düzelttim, ancak birden fazla örneği hakkında fikrinizi görmüyorum Foo. Onlarla doğru bir şekilde ilgilenmelidir.
terdon

@JohnDibling güncellemelere bakın.
terdon

1
100 satır "Foo" ve ardından "Bar" içeren bir dosya rapor etmez.
Stéphane Chazelas

0

Test edilmedi, telefonumdayım:

find . -name "*.cpp" | xargs awk '/foo/{t=$0;c=10}/bar/{c=0;t=""}c{c--}t&&!c{print t;t=""}END&&t{print t}' 

bunun gibi bir şey.

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.