regex - uso - hacer doble grep
Se necesita Regex(grep) para la búsqueda de varias líneas (3)
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 pestañas 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 sintaxis correcta, por favor?
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.
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 intento 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
).
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.