Regex (grep) per la ricerca su più righe necessario

Possibile duplicato:
Come posso cercare un pattern multilinea in un file? Usa pcregrep

Sto eseguendo un grep per trovare qualsiasi file * .sql che abbia la parola select seguita dalla parola customerName seguita dalla parola from . Questa istruzione select può estendersi su molte linee e può contenere tabulazioni e newline.

Ho provato alcune varianti su quanto segue:

 $ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0- 9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from" 

Questo, tuttavia, funziona per sempre. Qualcuno può aiutarmi con la syntax corretta per favore?

Senza la necessità di installare la variante grep pcregrep, puoi eseguire la ricerca multilinea con grep.

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

Spiegazione:

-P triggers perl-regexp per grep (una potente estensione delle estensioni regolari)

-z sopprime newline alla fine della riga, sottotitolo per carattere null. Cioè, grep sa dove è la fine della linea, ma vede l’input come una grande linea.

-o stampa solo la corrispondenza. Dato che stiamo usando -z , l’intero file è come un’unica grande linea, quindi se c’è una corrispondenza, l’intero file verrebbe stampato; in questo modo non lo farà.

In regexp:

(?s) triggers PCRE_DOTALL , il che significa che . trova qualsiasi carattere o newline

\N trova nulla tranne newline, anche con PCRE_DOTALL triggersto

.*? trovare in modalità non concreta, ovvero, si interrompe il prima ansible.

^ trova l’inizio della linea

\1 backreference al primo gruppo ( \s* ) Questa è una prova per trovare lo stesso rientro del metodo

Come puoi immaginare, questa ricerca stampa il metodo principale in un file sorgente C ( *.c ).

Non sono molto bravo in grep. Ma il tuo problema può essere risolto usando il comando AWK . Guarda

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

Il codice di cui sopra risulterà dalla prima occorrenza di select fino alla prima sequenza di from . Ora è necessario verificare se le dichiarazioni restituite abbiano o meno il nome utente. Per questo è ansible redirect il risultato. E puoi usare di nuovo awk o grep.

Il tuo problema fondamentale è che grep lavora una riga alla volta – quindi non riesce a trovare un’istruzione SELECT distribuita tra le righe.

Il tuo secondo problema è che la regex che stai usando non affronta la complessità di ciò che può apparire tra SELECT e FROM – in particolare, omette virgole, punti fermi (punti) e spazi vuoti, ma anche citazioni e tutto ciò che può essere all’interno una stringa quotata.

Probabilmente andrei con una soluzione basata su Perl, avendo Perl letto ‘paragrafi’ alla volta e applicando un’espressione regolare a quello. Il rovescio della medaglia sta avendo a che fare con la ricerca ricorsiva – ci sono moduli per farlo, naturalmente, incluso il modulo principale File :: Trova .

Di profilo, per un singolo file:

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

Questo deve essere racchiuso in un sub che viene quindi richiamato dai metodi di File :: Trova.