Belirli bir yoldaki bir dosyayı hariç tutarak grep komutunu çalıştırın


12

Dosyayı aramamın dışında tutmak istiyorum ./test/main.cpp.

İşte gördüğüm:

$ grep -r pattern --exclude=./test/main.cpp
./test/main.cpp:pattern
./lib/main.cpp:pattern
./src/main.cpp:pattern

Bir boru ve filtreler düzenlemesinde birden çok komut kullanarak istediğim çıktıyı elde etmenin mümkün olduğunu biliyorum, ancak grepdoğal olarak ne istediğimi anlayacak bazı alıntılar / kaçış var mı?


Çıktıyı filtrelemeye dayanan bir çözüm, ilişkili sonuçları dışlamadan önce gereksiz yere dosyayı aradığından iyi ölçeklenmez. Tüm dizinleri (ile --exclude-dir) hariç tutmak istersem sorun büyütülür . Bu yüzden grep'in dışlamayı yerel olarak gerçekleştirmesini istiyorum.
nobar


Yanıtlar:


6

grep farklı dizinlerde aynı ada sahip daha fazla dosyanız varsa, belirli bir dizindeki dosya için bunu yapamazsanız, bunun yerine find öğesini kullanın:

find . -type f \! -path './test/main.cpp' -exec grep pattern {} \+


Neden kaçıyorsun \!ve \+? Ters eğik çizgiler olmadan iyi çalışıyor gibi görünüyor.
nobar

@nobar Bazı karakterler kabuk anahtar kelimeler olduğu için alışkınım, bu yüzden asla şaşırmazsınız çünkü kaçarlarsa hiçbir şey olamaz.
MichalH

" grepBunu yapamam, findonun yerine kullan" - mükemmel.
nobar

4

GNU ile mümkün olduğunu sanmıyorum grep. Yine de borulara ihtiyacınız yok.

İle find:

find . ! -path ./test/main.cpp -type f -exec grep pattern {} +

İle zsh:

grep pattern ./**/*~./test/main.cpp(.)

(.git, .svn ... 'yi hariç tutmak için gizli dosyaları hariç tutar.).


2

Bir kitap yazabilirim: "Kayıp sanatı xargs". find ... -exec … ';Lansmanlar her dosya için bir grep (ama ile varyant -exec … +vermez). Bugünlerde CPU döngüleri harcıyoruz, neden olmasın, değil mi? Ancak performans ve bellek ve güç bir sorunsa: xargs kullanın:

find . -type f \! -path 'EXCLUDE-FILE' -print0 | xargs -r0 grep 'PATTERN'

GNU find'ın -print0edecek NULçıkış ve -terminate xargs' -0girdi olarak o biçim seçeneğini onur. Bu, dosyanızın komik karakterleri ne olursa olsun, ardışık düzen karışmaz. -rSeçenek emin durumda herhangi bir hata olmasa yapar findbulur şey.

Artık şu gibi şeyler yapabilirsiniz:

find . -type f -print0 | grep -z -v "FILENAME EXCLUDE PATTERN" | 
  xargs -r0 grep 'PATTERN'

GNU grep -z, xargs ile aynı şeyi yapar -0.


3
Bazı ilginç notlar, ancak performans sorununu doğru bulduğunuzdan emin değilim. Anladığım kadarıyla find -exec (cmd) {} +aynı şekilde xargsve aynı şekilde find -exec (cmd) {} \;çalışır xargs -n1. Başka bir deyişle, ifadeniz yalnızca \;sürüm kullanılıyorsa doğrudur .
nobar

3
İçine boru xargsbağlantısı -exec … +(marjinal de olsa) kullanmaktan daha az verimlidir . Buradaki cevapların hiçbiri söz bile etmiyor -exec … \;.
Gilles 'SO- kötü olmayı bırak'

1
Şey, s - t. Kendimle çıkıyorum. Yorumlar ve düzeltmeler için teşekkürler. \ + 'In bir yazım hatası olduğunu düşündüm. Oh bak, -exec ... +Ocak 2005'te eklendi. Evet, güncel değilim ... at all.
Otheus

2

Senin Eğer finddestekleri -path2008 yılında POSIX'e eklendi ama hala Solaris eksikti:

find . ! -path ./test/main.cpp -type f -exec grep pattern /dev/null {} +

1
Nobar diğer dizinlerde main.cpp istiyor çünkü işe yarayacağını sanmıyorum
Eric Renouf

1
deseniniz main.cpp dosyasını diğer tüm dizinlerden de hariç tutmayacak mı? Bu arzu edilmez
Eric Renouf

@EricRenouf: Hata, yanlış okuma. Cevabım güncellendi.
cuonglm

@Gilles: Neden -pathPOSIX değil?
cuonglm

Üzgünüm, hatam, 2008'de eklendi. Yine de Solaris'ten eksik.
Gilles 'SO- kötü olmayı bırak'

1

Kayıt için, tercih ettiğim yaklaşım:

grep pattern $(find . -type f ! -path './test/main.cpp')

grepKomutun başında tutarak, bunun biraz daha açık olduğunu düşünüyorum - artı greprenk vurgulamasını devre dışı bırakmıyor . Bir anlamda, findbir komut ikamesinde kullanmak, grepişlevlerinin (sınırlı) dosya arama alt kümesini genişletmenin / değiştirmenin bir yoludur .


Bana göre find -execsözdizimi bir çeşit sırtır. Bir karmaşıklık find -exec(bazen) çeşitli karakterlerden kaçma gereksinimidir (özellikle \;Bash altında kullanılıyorsa). Sadece şeyleri tanıdık bağlamlara koymak için, aşağıdaki iki komut temel olarak eşdeğerdir:

find . ! -path ./test/main.cpp -type f -exec grep pattern {} +
find . ! -path ./test/main.cpp -type f -print0 |xargs -0 grep pattern

Alt dizinleri hariç tutmak istiyorsanız , joker karakter kullanmak gerekebilir. Buradaki şemayı tam olarak anlamıyorum - gizli hakkında konuşun :

grep pattern $(find . -type f ! -path './test/main.cpp' ! -path './lib/*' )

Komut dosyalarında kullanılmak üzere genelleştirilmiş findçözümleri genelleştirmek için başka bir not : grepKomut satırı -H/ --with-filenameseçeneğini içermelidir . Aksi takdirde, arama sonuçlarında yalnızca bir dosya adı olması durumunda çıktı biçimlendirmesini değiştirir find. Bu, dikkate değerdir çünkü grepyerel dosya araması ( -rseçenekle birlikte) kullanılıyorsa gerekli görünmemektedir .

... Daha da iyisi, aranacak /dev/nullilk dosya olarak dahil etmektir. Bu iki sorunu çözer:

  • Aranacak bir dosya varsa, iki dosya olduğunu grepdüşünecek ve çoklu dosya çıktı modunu kullanacaktır.
  • Aranacak grepdosya yoksa, tek bir dosya olduğunu düşünecek ve stdin'de beklemeyecek.

Yani son cevap:

grep pattern /dev/null $(find . -type f ! -path './test/main.cpp')

findKomutunun çıktısını komut yerine kullanmamalısınız. Boşluk veya başka özel karakterler içeren dosya adları varsa bu durum bozulur. Kullanımı find -exec, sağlam ve kullanımı kolaydır.
Gilles 'SO- kötü olmayı bırak'

@Gilles: Çok iyi bir nokta - çıktı bazı programların komut satırı boyut sınırlarını da aşabilir. Uyarı emptor.
nobar

Ugh. 'find' sözdizimi çok zordur. '-o' bir "veya" operatörüdür (Linux üzerinde '-veya' da), ancak tipik kullanımı (örneğin '-prune' ile) kavramsal olarak mantıksal veya kavramıyla eşleşmez. İşlevsel veya mantıklı değil veya.
nobar

Diğer bir yolu bir isim eşleşen dayalı alt dizinleri dışlamak için: find -iname "*target*" -or -name 'exclude' -prune. Eh, bu bir tür çalışır - budanmış dizin listelenir, ancak aranmaz. Listelenmesini istemiyorsanız, bir tür gereksizlik ekleyebilirsiniz! -name 'exclude'
nobar
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.