Tengo un archivo de registro enorme y quiero seleccionar la primera aparición de un patrón, y luego encontrar otro patrón justo después de esta ocurrencia.
Por ejemplo:
123
XXY
214
ABC
182
558
ABC
856
ABC
En mi ejemplo, me gustaría encontrar 182
y luego encontrar la próxima aparición deABC
La primera aparición es simple:
grep -n -m1 "182" /var/log/file
Esto produce:
5:182
¿Cómo encuentro la próxima aparición de ABC?
Mi idea era decirle grep
que omita las primeras n
líneas (en el ejemplo anterior n=5
), según el número de línea de 182. Pero, ¿cómo hago eso?
grep
se utiliza? No creo que esto se pueda hacer,grep
pero sería fácil conawk
osed
(solo o en combinación congrep
).grep
no es obligatorio. Todavía no estoy tan familiarizado consed
oawk
. Si tienes una buena solución, ¡déjame escucharla! :) @don_crissti solo se debe imprimir la primera línea. No me importan las otras ocurrencias.Respuestas:
Con
sed
usted puede usar un rango yq
uit de entrada en una sola finalización:Del mismo modo con GNU
grep
, puede dividir la entrada entre dosgrep
s:... que imprime ...
... para indicar que el primero
grep
encontró un-F
literal de cadena ixed,-x
la línea completa 182 coincide con 5 líneas desde el comienzo de su lectura, y el segundo encontró un ABC de tipo similar con 2 líneas desde el comienzo de su lectura, o 2 líneas después de la primera lectura degrep
dejar en la línea 5.De
man grep
:Usé un documento aquí en aras de una demostración reproducible, pero probablemente debería hacer:
También funcionará con otras construcciones de comandos compuestos de shell como:
fuente
grep
's en lugar de un;
... no-gogrep
comparten es efectivamente una tubería para ellos. Algo más: intenté sin imprimir la línea de marcador perosed '//,/^ABC$/!d;/^ABC$/!d;q'
arroja un error extraño. ¿Qué//
hacer?sed
, solo lo escribí muy rápido.sed
cosa funciona, solo dejaste la referencia. Ensed
puede referirse al último/address/
nuevamente con una//
dirección vacía . Así que/^182$/command;//,/next_address/
solo lo hace/^182$/command;/^182$/,/next_address/
. Su error probablemente no fue una expresión regular previa si estaba usando un GNUsed
. Por cierto, lo de la búsqueda de tuberías se puede manipular por vía indirecta a través de los/dev/fd/[num]
enlaces en los sistemas Linux, pero si no tienes mucho cuidado para manejar bien los búferes (como condd
) , generalmente es una batalla perdida.Usar
grep
con expresiones regulares compatibles con Perl (pcregrep
):La opción
-M
permite que el patrón coincida con más de una línea y\K
no incluye un patrón coincidente (hasta este punto) en la salida. Puede eliminar\K
si desea tener toda la región como resultado.fuente
fuente
awk '/^182$/{z=1;next} z&&/^ABC$/{print NR":"$0;exit}' file
, o puede escribir al menos ungetline()
bucle explícito que generalmente es más torpe, o ser inteligente (?) usando un rango casi como el perl de @ JRFerguson:awk '!x&&/^182$/,/^ABC$/ {x=NR":"$0} END{print x}
Una variación de Perl que podrías usar es:
... que imprime líneas en el rango correspondiente.
Si el archivo contenía más de un rango coincidente, puede limitar la salida solo al primer rango cambiando el
/
delimitador a?
fuente
Siguiendo con solo
grep
y agregandotail
&cut
, podrías ...grep para el número de línea de la primera coincidencia de
182
:Use eso para grep para todos los
ABC
's solo después de la primera línea de coincidencia anterior, usandotail
' s-n +K
para salir después de la línea K'th. Todos juntos:O agregue
-m 1
nuevamente para encontrar solo la primera coincidenciaABC
Referencias:
man
páginas/programming/6958841/use-grep-to-report-back-only-line-numbers
fuente
Otra variante es esta:
La bandera -Un greps n líneas después del partido y 99999 es solo para asegurarse de que no nos perdamos nada. Los archivos más grandes deberían tener más líneas (consulte con "wc -l").
fuente
El operador de rango
,
se puede usar aquí:El operador de rango
..
junto con el operador de solo coincidencia una vezm??
se puede usar aquí enPerl
fuente