Bir dosyada çok satırlı bir modeli nasıl arayabilirim?


128

Belirli bir dize kalıbı içeren tüm dosyaları bulmam gerekiyordu. Akla gelen ilk çözüm, xargs grep ile borulu bul kullanmaktır :

find . -iname '*.py' | xargs grep -e 'YOUR_PATTERN'

Ancak birden fazla çizgiye yayılan desenler bulmam gerekirse, takılıyorum çünkü vanilya grep çok satırlı desenleri bulamıyor.



2
Bu daha eski, bu yüzden bir kopya olmadığını söyleyebilirim :)
rogerdpack

@rogerdpack Soruları yinelenen olarak işaretlerken, yanıtların miktarı ve kalitesinden ve sorunun kalitesinden sonra sorunun yaşı üçüncül bir sorundur.
üçlü

Yanıtlar:


98

Böylece , Perl Uyumlu Normal İfadeler GREP anlamına gelen pcregrep'i keşfettim .

Örneğin, 'dosyalarını bulmalıyız _name ' değişken immediatelly 'izlemektedir _description ' değişkeni:

find . -iname '*.py' | xargs pcregrep -M '_name.*\n.*_description'

İpucu: kalıbınıza satır sonu karakterini eklemeniz gerekir. Platformunuza bağlı olarak '\ n', \ r ',' \ r \ n ', ... olabilir


7
Aşağıda halka tarafından belirtildiği gibi, "normal ifadenize (ler) eklerseniz nokta joker karakterini yeni satırlarla eşleşmeye de ikna edebilirsiniz". Sonra perl regex ile grep'i -P ekleyerek kullanın. bul. -exec grep -nHP '(? s) SELECT. {1,60} BAŞLANGIÇ. {1,20} tablo_adı' '{}' \;
Jim

8
pcregrepMac'tebrew install pcre
Jared Beck

1
Daha da iyisi: Ayrıca kullanmak -Hher maçtan önce dosya adını yazdırır hangi: pcregrep -HM.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

97

Neden awk için gitmiyorsun :

awk '/Start pattern/,/End pattern/' filename

2
awkÇoğu * nix sistemiyle birlikte gelen bunu anlamak ve kullanmak çok daha kolaydır .
Ali Karbassi

24
Güzel! Bu eşleşmeyi açgözlü olmayan yapmanın bir yolu var mı?
marcin

3
Nasıl sadece bir eşleşme olduğunda dosya adını yazdırırsınız?
bibstha

2
İle maçların sıra numaralarını gösterebilirsiniz awk '/Start pattern/,/End pattern/ {printf NR " "; print}' filename. Bunu satır numaraları sabit genişlik vererek daha güzel yapabilirsiniz: awk '/Start pattern/,/End pattern/ {printf "%-4s ", NR; print}' filename.
Robert

Bu, tek bir dosyada iyi çalışıyor gibi görünüyor, ancak ya birden çok dosya içinde arama yapmak istersem?
Jinstrong

84

İşte GNUgrep kullanan örnek :

grep -Pzo '_name.*\n.*_description'

-z/ --null-dataGirdi ve çıktı verilerini satır dizileri olarak ele alın.

Ayrıca buraya bakın


1
Sanırım bu sadece tek bir yeni satır karakterini açıklıyor.
Bulut

1
Çok satırlı arama için grep'i bayrakları kullanmadan kullanamadım, -zbu yüzden tek satırda aramayı bölmez ve -oyalnızca eşleşen kısmı yazdırır.
bbaja42

Bunu buldum -o hiçbir şey yazdırmamasına neden oldu, ama grep -rzl pattern *-dosyaların bir listesini almak için çalıştım ( komutum, -rzo çalışmadı)
Benubird

5
ASCII olmayan dosyalar için "-Pzo" yerine " grep -Pazo " 'yu ​​öneririm. ASCII olmayan dosyaları üzerinde -z anahtarı, çünkü daha iyi olabilir dönüş değerini değiştirir grep yönettiği "ikili veri" davranışını tetikler. Anahtarı '' -a | --text '' bunu engeller.
rloth

Mac'te git yüklü olarak brew reinstall --with-pcre git
çalışmıyor

21

grep -Payrıca libpcre kullanır, ancak çok daha yaygın olarak yüklenir. titleBirden çok satıra yayılmış olsa bile, bir html belgesinin tam bir bölümünü bulmak için şunu kullanabilirsiniz:

grep -P '(?s)<title>.*</title>' example.html

Yana PCRE proje perl standardına uygular, başvuru için perl belgelere kullanın:


Hmm bunu şimdi denedi ve işe yaramadı ... gist.github.com/rdp/0286d91624930bd11d0169d6a6337c33
rogerdpack

Grep'in bu seçeneği olduğunu bilmiyordum . Muhtemelen şundan dolayı: Bu oldukça deneyseldir ve grep -P uygulanmayan özellikler konusunda uyarıda bulunabilir. ; bu CentOS 7 altındadır. Fedora 29 altında: Bu deneyseldir ve grep -P uygulanmayan özellikler konusunda uyarıda bulunabilir . Tabii ki BSD grep'te hiç orada değil. Bu kadar deneysel olmasaydı güzel olurdu ama hatırlatılması güzeldi - az da olsa kullanacağım.
Pryftan

17

İşte daha kullanışlı bir örnek:

pcregrep -Mi "<title>(.*\n){0,5}</title>" afile.html

Başlık etiketini bir html dosyasında 5 satıra kadar yayılmış olsa bile arar.

İşte sınırsız hatlara bir örnek:

pcregrep -Mi "(?s)<title>.*</title>" example.html 

4
Bunun için teşekkürler. Bir joker karakterin satırsonu karakteriyle eşleşmeyeceğini fark edemiyordum.
mat

7
@matt: Ayrıca, nokta joker karakterini (?s)normal ifadenize eklerseniz , yeni satırlarla eşleşecek şekilde ikna edebilirsiniz , örneğin:"(?s)<html>.*</html>"
lubomir.brindza

@matt Elbette $(bir desenin sonunda) bunun satırın sonu olduğunu belirtmek için kontrol edebilirsiniz - ancak bu, birden fazla çizgi desenini bulmanıza yardımcı olmakla aynı şey değildir. Ayrıca bakınız glob(7). Bu web sitesini de ilginizi çekebilecek bir web sitesinde bulabilirsiniz: düzenli
expressions.info


4

Grep alternatif elemesini burada kullanabilirsiniz (sorumluluk reddi: Ben yazarım).

Çok satırlı eşleşmeyi destekler ve aramayı kutunun dışında belirli dosya türleriyle sınırlandırır:

sift -m --files '* .py' 'YOUR_PATTERN'

(belirtilen çok satırlı normal ifade kalıbı için tüm * .py dosyalarında arama yapın)

Tüm büyük işletim sistemleri için mevcuttur. Bir XML dosyasından çok satırlı değerleri çıkarmak için nasıl kullanılabileceğini görmek için örnekler sayfasına bir göz atın .


3

Bu cevap faydalı olabilir:

Çok satırlı arama için normal ifade (grep) gerekli

Özyinelemeli bulmak için -R (özyinelemeli) ve --include (GLOB kalıbı) bayraklarını kullanabilirsiniz. Görmek:

Belirli dosyalar arasında grep olmamak için grep --exclude / - include sözdizimini kullanın


@ Ɖiamond ǤeezeƦ, LQP'de ( stackoverflow.com/review/low-quality-posts/19341146 ) bir gönderiyi düzenlemenin incelemeyi geçersiz kıldığına dikkat edin, bu nedenle, gönderinin korunması gerektiğinden eminseniz sadece düzenleyin.
fedorqui 'SO zarar vermeyi bırak'

2

@Marcin: açgözlü olmayan awk örneği:

awk '{if ($0 ~ /Start pattern/) {triggered=1;}if (triggered) {print; if ($0 ~ /End pattern/) { exit;}}}' filename

2
perl -ne 'print if (/begin pattern/../end pattern/)' filename

Bu, tüm dosyayı
Herbert

1

Kullanılması ex/ vieditörü ve globstar seçeneği (benzer sözdizimi awkve sed):

ex +"/string1/,/string3/p" -R -scq! file.txt

aaabaşlangıç ​​noktanız nerede ve bbbbitiş metniniz.

Yinelemeli arama yapmak için şunu deneyin:

ex +"/aaa/,/bbb/p" -scq! **/*.py

Not: **Sözdizimini etkinleştirmek için shopt -s globstar(Bash 4 veya zsh) çalıştırın .

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.