Se necesita Regex (grep) para la búsqueda de varias líneas

Posible duplicado:
¿Cómo puedo buscar un patrón de líneas múltiples en un archivo? Use pcregrep

Estoy ejecutando un grep para encontrar cualquier archivo * .sql que tenga la palabra select seguido de la palabra customerName seguido de la palabra from . Esta instrucción select puede abarcar muchas líneas y puede contener tabs y nuevas líneas.

He intentado algunas variaciones sobre lo siguiente:

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

Esto, sin embargo, solo se ejecuta para siempre. ¿Alguien puede ayudarme con la syntax correcta, por favor?

Sin la necesidad de instalar la variante grep pcregrep, puede hacer una búsqueda de líneas múltiples con grep.

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

Explicación:

-P activar perl-regexp para grep (una poderosa extensión de extensiones regulares)

-z suprime la nueva línea al final de la línea, subtitulándola para carácter nulo. Es decir, grep sabe dónde está el final de la línea, pero ve la entrada como una gran línea.

-o imprime solo coincidencia. Debido a que estamos usando -z , el archivo completo es como una sola línea grande, por lo que si hay una coincidencia, el archivo completo se imprimirá; de esta manera no hará eso.

En expresiones regulares:

(?s) activar PCRE_DOTALL , lo que significa que . encuentra cualquier personaje o nueva línea

\N encuentra nada excepto newline, incluso con PCRE_DOTALL activado

.*? encontrar . en modo no dirigido, es decir, se detiene lo antes posible.

^ encontrar inicio de línea

\1 retroreferencia al primer grupo ( \s* ) Este es un bash de encontrar la misma sangría de método

Como se puede imaginar, esta búsqueda imprime el método principal en un archivo fuente C ( *.c ).

No soy muy bueno en grep. Pero su problema puede resolverse utilizando el comando AWK . Sólo ve

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

El código anterior será el resultado de la primera aparición de select hasta la primera secuencia de from . Ahora necesita verificar si las declaraciones devueltas tienen nombre de customername o no. Para esto puedes canalizar el resultado. Y puede usar awk o grep nuevamente.

Su problema fundamental es que grep funciona una línea a la vez, por lo que no puede encontrar una instrucción SELECT distribuida entre líneas.

Su segundo problema es que la expresión regular que está utilizando no se ocupa de la complejidad de lo que puede aparecer entre SELECT y FROM, en particular, omite comas, puntos (espacios) y espacios en blanco, sino también comillas y cualquier cosa que pueda estar dentro una cadena citada.

Probablemente vaya con una solución basada en Perl, haciendo que Perl lea ‘párrafos’ a la vez y aplicando una expresión regular a eso. La desventaja es tener que lidiar con la búsqueda recursiva; hay módulos para hacer eso, por supuesto, incluido el módulo principal File :: Find .

En resumen, para un solo archivo:

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

Eso debe ser envuelto en un sub que luego es invocado por los métodos de File :: Find.