Regex (grep) para la búsqueda multilínea necesaria [duplicar]


Posible Duplicado:
¿Cómo puedo buscar un patrón multilínea en un archivo ? Use pcregrep

Estoy ejecutando un grep para encontrar cualquier *.archivo sql que tiene la palabra select seguida de la palabra customerName seguida de la palabra from. Esta instrucción select puede abarcar muchas líneas y puede contener pestañas y nuevas líneas.

He probado 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. ¿Puede alguien ayudarme con el sintaxis correcta por favor?

Author: Community, 2010-09-15

3 answers

Sin necesidad de instalar la variante de grep pcregrep, puede realizar búsquedas multilínea con grep.

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

Explicación:

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

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

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

En expresiones regulares:

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

\N encuentra cualquier cosa excepto nueva línea, incluso con PCRE_DOTALL activado

.*? buscar . en modo nongreedy, es decir, se detiene tan pronto como sea posible.

^ buscar inicio de línea

\1 backreference to first group (\s*) Este es un intento de encontrar lo mismo sangría del método

Como puede imaginar, esta búsqueda imprime el método principal en un archivo fuente 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-15 12:49:44

No soy muy bueno en grep. Pero su problema se puede resolver usando el comando AWK . Solo ver

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 instrucciones devueltas tienen customername o no. Para esto se puede canalizar el resultado. Y puede usar awk o grep de nuevo.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-21 10:32:44

Su problema fundamental es que grep funciona una línea a la vez, por lo que no puede encontrar una instrucción SELECT repartida 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 completos (puntos) y espacios en blanco, sino también comillas y cualquier cosa que pueda estar dentro de una cadena entre comillas.

Probablemente iría con una solución basada en Perl, haciendo que Perl leyera '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, incluyendo el módulo principal File::Find.

En el esquema, para un solo archivo:

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

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

Que necesita ser envuelto en un sub que luego es invocado por los métodos de 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-15 13:11:21