¿Cómo obtener texto del rango de fechas usando grep / sed en un archivo de texto grande?

9

Tengo texto de archivo grande (casi 3 GB): es un archivo de registro. Quiero obtener líneas de texto que correspondan a un rango de fechas de este archivo, del 13 de julio al 19 de julio. Mi formato de registro es:

2016-07-12 < ?xml version>
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
2016-07-20 < ?xml version>
sample text sample text
sample text sample text
sample text sample text
2016-07-20 < ?xml version>
sample text sample text
2016-07-20 < ?xml version>

así que después grep/ seddebería salir así:

2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>

¿Cómo puedo conseguir esto?

corey
fuente
2
¿Estás seguro de que te refieres a junio ? Todas las fechas en su archivo de registro de muestra son en julio y la muestra de salida deseada implica que se refería a esto último.
David Foerster

Respuestas:

13

Con grepsi se conoce el número de líneas que desea opción de contexto se puede utilizar -Apara imprimir líneas según el modelo

grep -A 3 2016-07-13 file

eso te dará la línea con 2013-07-13 y las siguientes 3 líneas

con sedusted puede usar las fechas para delimitar así

sed -n '/2016-07-13/,/2016-07-19/p' file

que imprimirá todas las líneas desde la primera línea con 2016-07-13 hasta e incluyendo la primera línea con 2016-07-19. Pero eso supone que solo tiene una línea con 2016-07-19 (no imprimirá la siguiente línea). Si hay varias líneas, use la siguiente fecha en su lugar y use dpara eliminar la salida de ella

sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file
Zanna
fuente
4

awk solución:

$ awk '/^2016-07-13.*/,/2016-07-19.*/'  input.txt                                   
2016-07-13 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-19 < ?xml version> 

Básicamente imprime cualquier línea desde la que comienza con 2016-07-13la que comienza con2016-07-19

Sergiy Kolodyazhnyy
fuente
4

Todas las demás respuestas actuales se basan en el hecho de que las entradas del archivo de registro se ordenan cronológicamente o en el hecho de que el intervalo de fechas se puede combinar fácilmente con expresiones regulares. Si desea una solución más genérica, necesitamos hacer más programación.

Les presento este script GNU AWK:

#!/usr/bin/gawk -f
BEGIN {
    starttime = mktime(starttime)
    endtime = mktime(endtime)
}

func in_range(n, start, end) {
    return start <= n && n < end
}

match($0, /^([0-9]{4})-([0-9]{2})-([0-9]{2})\s/, m) &&
    in_range(mktime(m[1] " " m[2] " " m[3] " 00 00 00"), starttime, endtime)

Proporciona el tiempo de inicio y finalización a través de las variables starttimey endtimeen un formato que mktimecomprende ( YYYY MM DD hh dd ss). Por lo tanto, ejecuta el awkcomando de esta manera, suponiendo que el script Awk anterior está en un archivo ejecutable filter-log-dates.awken el directorio de trabajo actual y el archivo de registro es mylog.txt:

./filter-log-dates.awk -v starttime='2016 07 13 00 00 00' -v endtime='2016 07 20 00 00 00' mylog.txt

Tenga en cuenta que la hora de finalización es exclusiva , es decir, los registros de registro válidos deben tener una marca de tiempo antes de la hora de finalización.

Si su formato de marca de tiempo es diferente, puede ajustar la expresión regular pasada a la matchfunción para adaptarla.

David Foerster
fuente
3

Podrías hacerlo en pasos. Encuentre el número de la primera línea que coincida con su patrón inicial. Encuentra el número de la última línea que coincide con tu patrón final. Luego extraiga la prueba entre estas dos líneas. Esto puede hacerse de la siguiente manera.

grep -n 2016-07-13 bigtextfile | head -1
grep -n 2016-07-19 bigtestfile | tail -1
# Say the first number is 1234 and the second 5678, then use...
awk 'NR>=1234 && NR<=5678' bigtestfile > rangeoftext

Esto podría hacerse todo en un awkcomando, pero los pasos pueden facilitar su seguimiento. Dentro de awk, la variable NR es el número de línea actual, y dado que no se especificó ninguna acción después del patrón (NR> = 1234 && NR <= 5678), la acción predeterminada es imprimir las líneas que están en ese rango.

Jeffrey Ross
fuente