Grep patrón multilínea


13

¿Cómo busco una frase en varias líneas? Por ejemplo, tengamos la frase "mi té helado", entonces puede estar envuelto en archivos de texto:

as js skdfh dfh djh sf my
ice tea.

grep no coincidirá ya que hay una nueva línea en el medio. ¿Cómo hago coincidir esos? Otro patrón multilínea seríapattern1_\n_pattern2

Sé que la forma más fácil de hacer ATM es solo grep por una parte, por ejemplo, solo hielo con la bandera -A2 -B2 y luego en esa salida, por ejemplo, té. Pero esto es muy tedioso. Así que estoy interesado en cómo resolverías esto.


Respuestas:


16

Puede instalar pcregrep(disponible en la mayoría de los repositorios de distribución), que es grep utilizando la biblioteca pcre , que hace "Expresiones regulares compatibles con Perl". Tiene una opción de línea de comando -Mque le permite realizar búsquedas multilínea, desde la página del manual :

"La salida para cualquier coincidencia puede consistir en más de una línea".

Entonces podrías hacer

pcregrep -M 'my\s+ice\s+tea' filename

El \sespacio en blanco es, que coincidirá \ny \ren modo multilínea, además de los caracteres en blanco normales. También puede hacer coincidir el carácter de nueva línea directamente, por lo que podría hacer

pcregrep -M 'pattern1_\n_pattern2' filename

+1 bien. Nunca he oído hablar de él, ¡pero lo probé y funciona de maravilla!
DaveParillo

¿No grep -Ehace patrones de pcre?
Daenyth

3
@Daenyth grep -E su mayoría sólo significa que puede utilizar ?, +, {, |, (, y )como su significado habitual de expresiones regulares sin tener que tener un \ frente, como lo hace si se utiliza grep estándar. Entonces grep 'hello\s\+world' filees equivalente a grep -E 'hello\s+world' file. No hace PCRE. Hay grep -Ppara expresiones regulares perl, pero es experimental (de acuerdo con la página del manual) y creo que es un poco diferente de pcregrep ...
Hamish Downer

1
Sí, estaba pensando -Pcuando dije -E, pero no me di cuenta de que era diferente.
Daenyth

3

Probablemente haría una búsqueda usando vimel :vimgrepcomando. Esto funciona de una manera vagamente similar a la de greppero admite vim REs y rutas.

Básicamente, ejecuta algo como :vimgrep 'pattern1\npattern2' path/**una búsqueda recursiva, luego escribe :copenpara que aparezca una ventana más pequeña que contiene una lista de coincidencias.

vimLos RE pueden hacer casi todo lo que los PCRE pueden hacer, pero evolucionaron por separado del linaje de expresiones regulares perl, por lo que la mayoría de las cosas avanzadas funcionan de manera diferente. Su funcionalidad básica es más parecida a la de los RE básicos, pero tienen algunas adiciones ingeniosas que los PCRE no ofrecen.

No estoy seguro de si es posible :vimgrepescupir datos como lo grephace; Solo he tratado de usarlo para navegar dentro vim.

:help vimgrepdesde dentro vimpara más información; :help pattern.txtpara información sobre vimREs; para más información sobre caminos ver :help wildcards.


Tenga cuidado: eso no es del todo portátil, ya que se comportará de manera diferente en diferentes plataformas
Daenyth

1
@Daenyth: ¿quieres decir bajo la influencia de diferentes .vimrc? Debería ser más portátil que grepcon respecto al sistema operativo: vimno tiene un "sabor POSIX" y funciona de manera más o menos idéntica incluso en Windows. .................................................. ........................... Es posible agregar calificadores para garantizar que, por ejemplo, se use la cantidad correcta de "magia" en el RE, Según tengo entendido, hay una estricta regla no escrita para dejar esa opción en paz.
intuido

No lo he usado yo mismo, pero aparentemente usa un backend diferente en Windows (en find.exelugar de grep). Hubo otra pregunta en las últimas semanas que tuvo ese problema.
Daenyth

1
@Daenyth: ¿Estás pensando en :vimgrepo :grep? De :help grep: "La ventaja del grep interno [es decir :vimgrep] es que funciona en todos los sistemas y utiliza los poderosos patrones de búsqueda de Vim".
intuido

1
Ah, eso debe ser. Los confundí a los dos.
Daenyth

2

Grep solo funciona en una línea a la vez, pero puede usar awk para imprimir líneas que coincidan con una variedad de patrones:

cat file | awk '/foo/,/bar/'

coincidiría con cualquier cosa, no solo con nuevas líneas entre los dos patrones


0

Para aprovechar al máximo Unix, debe aprovechar las tuberías. Puede hacer esto en forma simple grepusando tuberías (sin necesidad de tee):

$ grep -A1 "pattern1" file.txt |  grep "pattern2"

Lo cual no consideraría tedioso.


Creo que esto es propenso a errores, ya que entre pattern1 y pattern2 puede existir pattern3 que podría no ser lo que estás buscando. Entonces debes controlar cada golpe manualmente.
matemáticas
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.