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 182y 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 grepque omita las primeras nlíneas (en el ejemplo anterior n=5), según el número de línea de 182. Pero, ¿cómo hago eso?

grepse utiliza? No creo que esto se pueda hacer,greppero sería fácil conawkosed(solo o en combinación congrep).grepno es obligatorio. Todavía no estoy tan familiarizado consedoawk. 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
sedusted puede usar un rango yquit de entrada en una sola finalización:Del mismo modo con GNU
grep, puede dividir la entrada entre dosgreps:... que imprime ...
... para indicar que el primero
grepencontró un-Fliteral de cadena ixed,-xla 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 degrepdejar 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-gogrepcomparten 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.sedcosa funciona, solo dejaste la referencia. Ensedpuede 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
grepcon expresiones regulares compatibles con Perl (pcregrep):La opción
-Mpermite que el patrón coincida con más de una línea y\Kno incluye un patrón coincidente (hasta este punto) en la salida. Puede eliminar\Ksi 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
grepy 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 +Kpara salir después de la línea K'th. Todos juntos:O agregue
-m 1nuevamente para encontrar solo la primera coincidenciaABCReferencias:
manpá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í enPerlfuente