Regex (grep) dla potrzeb wyszukiwania wieloliniowego [duplikat]

Możliwy duplikat:
Jak wyszukać wzorzec wielowierszowy w pliku ? Użyj pcregrep

Uruchamiam grep, aby znaleźć*.plik sql zawierający słowo select, po którym następuje słowo customerName, po którym następuje słowo from. Ta instrukcja select może obejmować wiele linii i może zawierać tabulatory i nowe linie.

Wypróbowałem kilka wariacji na temat:

$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"
To jednak trwa wiecznie. Czy ktoś może mi pomóc w poprawną składnię proszę?
Author: Community, 2010-09-15

3 answers

Bez konieczności instalowania wariantu grep pcregrep, możesz przeszukiwać wiele linii za pomocą grepa.

$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c

Wyjaśnienie:

-P activate perl-regexp for grep (potężne rozszerzenie regularnych rozszerzeń)

-z wyłącza znak nowego wiersza na końcu wiersza z napisami dla znaku null. Oznacza to, że grep wie, gdzie znajduje się koniec linii, ale widzi wejście jako jedną dużą linię.

-o Drukuj tylko pasujące. Ponieważ używamy -z, cały plik jest jak pojedynczy duża linia, więc jeśli jest dopasowanie, cały plik zostanie wydrukowany; w ten sposób nie zrobi tego.

W regexp:

(?s) Aktywuj PCRE_DOTALL, co oznacza, że . znajdzie dowolny znak lub nową linię

\N znajdź wszystko oprócz nowej linii, nawet z PCRE_DOTALL aktywowaną

.*? Znajdź . w trybie niestandardowym, czyli zatrzymuje się tak szybko, jak to możliwe.

^ znajdź początek linii

\1 backreference to first group (\s*) jest to próba znalezienia tego samego wcięcie metody

Jak można sobie wyobrazić, to wyszukiwanie wyświetla główną metodę w pliku źródłowym C (*.c).

 390
Author: albfan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 12:49:44

Nie jestem zbyt dobry w grep. Ale twój problem można rozwiązać za pomocą polecenia AWK. Zobacz

awk '/select/,/from/' *.sql

Powyższy kod będzie wynikał od pierwszego wystąpienia select do pierwszego ciągu from. Teraz musisz sprawdzić, czy zwrócone polecenia mają customername, czy nie. W tym celu można rur wynik. I może ponownie użyć awk lub grep.

 143
Author: Amit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-21 10:32:44

Twój podstawowy problem polega na tym, że grep działa po jednej linijce na raz - więc nie może znaleźć instrukcji SELECT rozłożonej na linie.

Twój drugi problem polega na tym, że używane wyrażenia regularne nie radzą sobie ze złożonością tego, co może pojawić się między SELECT I FROM - w szczególności pomija przecinki, kropki i spacje, ale także cudzysłowy i wszystko, co może być wewnątrz cytowanego ciągu.

Prawdopodobnie wybrałbym rozwiązanie oparte na perlu, gdy Perl czyta "akapity" na raz i zastosowanie do tego wyrażenia regularnego. Minusem jest konieczność radzenia sobie z rekurencyjnym wyszukiwaniem - oczywiście istnieją moduły, które to robią, w tym moduł podstawowy File:: Find .

W zarysie, dla pojedynczego pliku:

$/ = "\n\n";    # Paragraphs

while (<>)
{
     if ($_ =~ m/SELECT.*customerName.*FROM/mi)
     {
         printf file name
         go to next file
     }
}

To musi być zawinięte w sub, który jest wywoływany przez metody File:: Find.

 6
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-15 13:11:21