¿Cómo busco múltiples patrones en múltiples líneas?

Respuestas:

14

Actualizado el 18 de noviembre de 2016 (dado que el comportamiento de grep ha cambiado: grep con el parámetro -P ahora no es compatible ^y $ancla [en Ubuntu 16.04 con kernel v: 4.4.0-21-generic]) ( corrección incorrecta (no) )

$ grep -Pzo "begin(.|\n)*\nend" file
begin
Some text goes here.  
end

nota: para otros comandos simplemente reemplace los anclajes '^' y '$' con el ancla de nueva línea '\n' ______________________________

Con el comando grep:

grep -Pzo "^begin\$(.|\n)*^end$" file

Si desea no incluir los patrones "comienzo" y "fin" en el resultado, use grep con soporte Lookbehind y Lookahead.

grep -Pzo "(?<=^begin$\n)(.|\n)*(?=\n^end$)" file

También puede usar la \Knotificación en lugar de la aserción Lookbehind.

grep -Pzo "^begin$\n\K(.|\n)*(?=\n^end$)" file

\KLa opción ignorar todo antes de la coincidencia de patrones e ignorar el patrón mismo.
\nSe utiliza para evitar imprimir líneas vacías desde la salida.

O como @AvinashRaj sugiere que hay grep simple y simple de la siguiente manera:

grep -Pzo "(?s)^begin$.*?^end$" file

grep -Pzo "^begin\$[\s\S]*?^end$" file

(?s)le dice a grep que permita que el punto coincida con los caracteres de nueva línea.
[\s\S]coincide con cualquier carácter que sea espacio en blanco o no espacio en blanco.

Y su salida sin incluir "comenzar" y "finalizar" es la siguiente:

grep -Pzo "^begin$\n\K[\s\S]*?(?=\n^end$)" file # or grep -Pzo "(?<=^begin$\n)[\s\S]*?(?=\n^end$)"

grep -Pzo "(?s)(?<=^begin$\n).*?(?=\n^end$)" file

vea la prueba completa de todos los comandos aquí ( desactualizado ya que se modifica el comportamiento grep con el parámetro -P )

Nota:

^señalar el comienzo de una línea y $señalar el final de una línea. estos se agregaron a "comenzar" y "terminar" para unirlos si están solos en una línea.
En dos comandos escapé $porque también lo uso para "Sustitución de comandos" ( $(command)) que permite que la salida de un comando reemplace el nombre del comando.

Del hombre grep:

-o, --only-matching
      Print only the matched (non-empty) parts of a matching line,
      with each such part on a separate output line.

-P, --perl-regexp
      Interpret PATTERN as a Perl compatible regular expression (PCRE)

-z, --null-data
      Treat the input as a set of lines, each terminated by a zero byte (the ASCII 
      NUL character) instead of a newline. Like the -Z or --null option, this option 
      can be used with commands like sort -z to process arbitrary file names.
αғsнιη
fuente
cambie su grep como grep -Pzo "(?<=begin\n)(.|\n)*(?=\nend)" filepara no imprimir el \ncarácter que existe en la línea de inicio.
Avinash Raj
Utilice el modificador DOTALL para hacer que el punto coincida incluso con los caracteres de nueva línea tambiéngrep -Pzo "(?s)begin.*?end" file
Avinash Raj el
O simplemente,grep -Pzo "begin[\s\S]*?end" file
Avinash Raj
1
La solución no funciona. Produce un error: grep: ein nicht geschütztes ^ oder $ wird mit -Pz nicht unterstütztla traducción del error es algo así como:grep: a not protected ^ or $ is not supported with -Pz
musbach
1
Sí, lo sé, eso está en tu respuesta. Estoy seguro de que funcionó cuando publicaste esto, pero vuelve a intentarlo hoy. El comportamiento de grepparece haber cambiado.
terdon
2

En caso de grepque no admita la sintaxis perl ( -P), puede intentar unir las líneas, hacer coincidir el patrón y luego expandir las líneas nuevamente como se muestra a continuación:

$ tr '\n' , < foo.txt | grep -o "begin.*end" | tr , '\n'
begin
Some text goes here.
end
kenorb
fuente