Wzór wielowierszowy Grep

13

Jak wyszukiwać frazy w wielu wierszach? Np. Pozwólmy, aby wyrażenie „moja mrożona herbata” mogło być zawinięte w pliki tekstowe:

as js skdfh dfh djh sf my
ice tea.

grep nie pasuje, ponieważ pomiędzy nimi jest nowa linia. Jak mogę je dopasować? Innym wzorem byłby wieloliniowypattern1_\n_pattern2

Wiem, że najłatwiejszym sposobem, w jaki robię bankomat, jest po prostu grep dla jednej części, np. Po prostu lód z flagą -A2 -B2, a następnie w tym wyjściu, na przykład dla herbaty. Ale to jest bardzo nużące. Ciekawi mnie więc, jak byś to rozwiązał.

matematyka
źródło
1
możliwy duplikat witryny: stackoverflow.com/questions/152708/...
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Odpowiedzi:

16

Możesz zainstalować pcregrep(dostępny w większości repozytoriów dystrybucji) - co jest grep przy użyciu biblioteki pcre , która wykonuje „wyrażenia regularne zgodne z Perl”. Posiada opcję wiersza poleceń -M, który pozwala zrobić multilinii wyszukiwań - od strony człowieka :

„Dane wyjściowe dla dowolnego dopasowania mogą składać się z więcej niż jednego wiersza”.

Więc możesz to zrobić

pcregrep -M 'my\s+ice\s+tea' filename

Jest \sto biały znak , który będzie pasował \noraz \rw trybie wielowierszowym, oprócz zwykłych znaków białych znaków. Możesz także dopasować znak nowej linii bezpośrednio, więc możesz to zrobić

pcregrep -M 'pattern1_\n_pattern2' filename
Hamish Downer
źródło
+1 fajnie. nigdy o tym nie słyszałem, ale próbowałem i działa jak urok!
DaveParillo
Czy nie grep -Ewykonuje się wzorów pcre?
Daenyth,
3
@Daenyth grep -E przeważnie po prostu oznacza, że można użyć ?, +, {, |, (, i )jak ich zwykłym znaczeniu regex bez konieczności mieć \ z przodu, jak to zrobić, jeśli używasz standardowego grep. Więc grep 'hello\s\+world' filejest równoważna grep -E 'hello\s+world' file. To nie robi PCRE. Jest grep -Pdla wyrażeń regularnych perla, ale jest eksperymentalny (według strony podręcznika) i myślę, że różni się nieco od pcregrep ...
Hamish Downer
1
Tak, myślałem o tym, -Pkiedy to powiedziałem -E, ale nie zdawałem sobie sprawy, że było inaczej.
Daenyth,
3

I prawdopodobnie nie szukaj używając vim„s :vimgreppolecenie. Działa to w sposób nieco podobny do tego, grepale obsługuje RE i ścieżki vim.

Zasadniczo uruchamiasz coś w rodzaju :vimgrep 'pattern1\npattern2' path/**wyszukiwania rekurencyjnego, a następnie piszesz, :copenaby wyświetlić mniejsze okno zawierające listę dopasowań.

vimRE mogą robić głównie wszystko, co PCRE, ale ewoluowały niezależnie od linii wyrażeń regularnych Perla, więc większość zaawansowanych rzeczy działa inaczej. Ich podstawowa funkcjonalność jest bardziej podobna do podstawowych RE, ale mają kilka ciekawych dodatków, których nie oferują PCRE.

Nie jestem pewien, czy da się :vimgrepwypluć dane tak jak grepto; Próbowałem go używać tylko do nawigacji wewnątrz vim.

:help vimgrepod wewnątrz, vimaby uzyskać więcej informacji; :help pattern.txtdla informacji o vimRE; Aby uzyskać więcej informacji na temat ścieżek zobacz :help wildcards.

intuicyjny
źródło
Uważaj - nie jest to całkowicie przenośne, ponieważ będzie zachowywać się inaczej na różnych platformach
Daenyth,
1
@ Daenyth: masz na myśli pod wpływem różnych .vimrc? Powinien być bardziej przenośny niż grepw odniesieniu do systemu operacyjnego: vimnie ma „posixowego smaku” i działa mniej więcej identycznie, nawet w systemie Windows. .................................................. ........................... Możliwe jest dodanie kwalifikatorów, aby zapewnić, że np. Odpowiednia ilość „magii” zostanie wykorzystana w RE jak rozumiem, istnieje surowa niepisana zasada, aby pozostawić tę opcję samemu sobie.
intuicyjnie,
Sam go nie użyłem, ale widocznie używa innego backendu w systemie Windows ( find.exezamiast grep). W ciągu ostatnich kilku tygodni było inne pytanie, które dotyczyło tego problemu.
Daenyth,
1
@Daenyth: Czy myślisz o :vimgreplub :grep? From :help grep: „Zaletą wewnętrznego grep [tj. :vimgrep] Jest to, że działa on na wszystkich systemach i wykorzystuje zaawansowane wzorce wyszukiwania Vima”.
intuicyjnie,
1
Ach, to musi być to. Zmieszałem tych dwóch.
Daenyth,
2

Grep działa tylko na jednej linii na raz, ale możesz użyć awk do drukowania linii pasujących do szeregu wzorów:

cat file | awk '/foo/,/bar/'

pasowałoby do wszystkiego, nie tylko nowych linii między tymi dwoma wzorami

DaveParillo
źródło
0

Aby w pełni wykorzystać uniks, musisz skorzystać z potoków. Możesz to zrobić w zwykły sposób grepza pomocą rur (nie potrzebujesz trójnika):

$ grep -A1 "pattern1" file.txt |  grep "pattern2"

Którego nie uważałbym za nudne.

Baruch
źródło
Myślę, że jest to podatne na błędy, ponieważ między wzorcem 1 a wzorcem 2 może istnieć wzór 3, który może nie być tym, czego szukasz. Musisz więc kontrolować każde trafienie ręcznie.
matematyka