¿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.

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.