Parece que estoy haciendo mal uso grep
/ egrep
.
Estaba tratando de buscar cadenas en varias líneas y no pude encontrar una coincidencia mientras sé que lo que estoy buscando debería coincidir. Originalmente pensé que mis expresiones regulares estaban mal, pero finalmente leí que estas herramientas funcionan por línea (también mis expresiones regulares eran tan triviales que no podía ser el problema).
Entonces, ¿qué herramienta se usaría para buscar patrones en varias líneas?
grep
. Están estrechamente relacionados pero no dups, en mi opinión."grep"
sugiere el verbo "to grep", y las respuestas principales, incluidas las aceptadas, no usan grep.Respuestas:
Aquí hay
sed
uno que le dará ungrep
comportamiento similar en varias líneas:Cómo funciona
-n
suprime el comportamiento predeterminado de imprimir cada línea/foo/{}
le indica que coincidafoo
y haga lo que viene dentro de los garabatos a las líneas coincidentes. Reemplacefoo
con la parte inicial del patrón.:start
es una etiqueta de ramificación que nos ayuda a seguir en bucle hasta que encontremos el final de nuestra expresión regular./bar/!{}
ejecutará lo que hay en los squigglies a las líneas que no coincidenbar
. Reemplazarbar
con la parte final del patrón.N
agrega la siguiente línea al búfer activo (sed
llama a esto el espacio del patrón)b start
se ramificará incondicionalmente a lastart
etiqueta que creamos anteriormente para seguir agregando la siguiente línea siempre que el espacio del patrón no contengabar
./your_regex/p
imprime el espacio del patrón si coincideyour_regex
. Debería reemplazarloyour_regex
por la expresión completa que desea hacer coincidir en varias líneas.fuente
sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
sed: unterminated {
errorsed
implementaciones. Traté de seguir las recomendaciones de esa respuesta para que el script anterior cumpliera con los estándares, pero me dijo que "inicio" era una etiqueta indefinida. Por lo tanto, no estoy seguro de si esto se puede hacer de una manera que cumpla con los estándares. Si lo logras, no dudes en editar mi respuesta.Generalmente uso una herramienta llamada
pcregrep
que se puede instalar en la mayoría de los sabores de Linux usandoyum
oapt
.Por ej.
Supongamos que si tiene un archivo
testfile
con contenidoPuede ejecutar el siguiente comando:
para hacer coincidir patrones en varias líneas.
Además, también puedes hacer lo mismo
sed
.fuente
Aquí hay un enfoque más simple con Perl:
o (como JosephR tomó la
sed
ruta , robaré su sugerencia descaradamente )Explicación
$f=join("",<>);
: esto lee todo el archivo y guarda su contenido (líneas nuevas y todo) en la variable$f
. Luego intentamos hacer coincidirfoo\nbar.*\n
e imprimir si coincide (la variable especial$&
contiene la última coincidencia encontrada). Se///m
necesita para hacer que la expresión regular coincida en las nuevas líneas.La
-0
fija el separador de registro de entrada. Establecer esto para00
activar el 'modo de párrafo' donde Perl usará nuevas líneas consecutivas (\n\n
) como separador de registros. En los casos en que no hay nuevas líneas consecutivas, todo el archivo se lee (sorbe) a la vez.Advertencia:
No no hacer esto para archivos de gran tamaño, se carga el archivo en la memoria y que puede ser un problema.
fuente
Una forma de hacerlo es con Perl. Por ejemplo, aquí está el contenido de un archivo llamado
foo
:Ahora, aquí hay algunos Perl que coincidirán con cualquier línea que comience con foo seguida de cualquier línea que comience con barra:
El Perl, desglosado:
while(<>){$all .= $_}
Esto carga toda la entrada estándar en la variable$all
while($all =~
Mientras que la variableall
tiene la expresión regular .../^(foo[^\n]*\nbar[^\n]*\n)/m
El regex: foo al comienzo de la línea, seguido de cualquier número de caracteres que no sean de nueva línea, seguido de una nueva línea, seguida inmediatamente por "barra", y el resto de la línea con barra en ella./m
al final de la expresión regular significa "hacer coincidir varias líneas"print $1
Imprima la parte de la expresión regular que estaba entre paréntesis (en este caso, la expresión regular completa)s/^(foo[^\n]*\nbar[^\n]*\n)//m
Borre la primera coincidencia para la expresión regular, de modo que podamos hacer coincidir múltiples casos de la expresión regular en el archivo en cuestiónY la salida:
fuente
perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo
La alternativa grep tamizar admite la coincidencia de varias líneas (exención de responsabilidad: yo soy el autor).
Supongamos que
testfile
contiene:sift -m '<description>.*?</description>'
(muestre las líneas que contienen la descripción)Resultado:
sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename
(extraer y reformatear la descripción)Resultado:
fuente
Simplemente un grep normal que admite
Perl-regexp
parámetrosP
hará este trabajo.(?s)
llamado modificador DOTALL que hace que el punto en su expresión regular coincida no solo con los caracteres sino también con los saltos de línea.fuente
-P
opciónResolví este para mí usando grep y la opción -A con otro grep.
La opción -A 1 imprime 1 línea después de la línea encontrada. Por supuesto, depende de su combinación de archivo y palabra. Pero para mí fue la solución más rápida y confiable.
fuente
Supongamos que tenemos el archivo test.txt que contiene:
Se puede usar el siguiente código:
Para el siguiente resultado:
fuente
Si queremos obtener el texto entre los 2 patrones excluyéndose a sí mismos.
Supongamos que tenemos el archivo test.txt que contiene:
Se puede usar el siguiente código:
Para el siguiente resultado:
¿Cómo funciona? Vamos a hacerlo paso a paso.
/foo/{
se activa cuando la línea contiene "foo"n
reemplace el espacio del patrón con la siguiente línea, es decir, la palabra "aquí"b gotoloop
pasar a la etiqueta "gotoloop":gotoloop
define la etiqueta "gotoloop"/bar/!{
si el patrón no contiene "barra"h
reemplace el espacio de espera con el patrón, por lo que "aquí" se guarda en el espacio de esperab loop
bifurcarse a la etiqueta "loop":loop
define la etiqueta "loop"N
agrega el patrón al espacio de espera.Ahora mantenga el espacio contiene:
"aquí"
"es el"
:gotoloop
Ahora estamos en el paso 4 y recorremos hasta que una línea contenga "barra"/bar/
el ciclo está terminado, se ha encontrado la "barra", es el espacio del patróng
el espacio del patrón se reemplaza con el espacio de espera que contiene todas las líneas entre "foo" y "bar" que se han guardado durante el bucle principalp
copia el espacio del patrón a la salida estándarHecho !
bucle multilínea sed
fuente