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?
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
).
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.
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.
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