¿Cómo cortar parte del archivo de registro?

18

Tengo un archivo de registro de 8 Gb (registro de producción de Rails). Necesito cortarlo entre algunas fechas (líneas). ¿Qué comando podría usar para hacer esto?

Eric Leschinski
fuente
1
Hola chicos, esta pregunta es sobre un archivo grande , así que es "¡Ante!" ... el tiempo importa ... He probado el script sed preferido en un archivo real de 8 GB, con 85904064 líneas (100 caracteres por línea). Me encanta sed, pero tal como está, el script sed escanea todo el archivo, cada vez. Esto hace que, en promedio, sea dos veces más lento que el script awk que sale cuando se encuentra ... Creo que (?) El script sed puede necesitar aq en lugar de d para la segunda expresión ... Los resultados de la prueba están aquí: pegar .ubuntu.com / 573477 .. Además, no produce la salida adecuada ... vea mi comentario al final de la respuesta de un sonido.
Peter
La nueva versión sed de asoundmove había abordado el problema de la velocidad, y ahora coincide con la velocidad de awks. y la nueva versión ahora genera datos correctamente ... vea sus comentarios para más detalles.
Peter.O
Me acabo de dar cuenta de que dijiste "cortar" (que generalmente significa eliminar) ... ¿Realmente quieres decir "cortar" o "copiar"? .... Si quisiste decir "cortar", entonces sedlo harás fácilmente.
Peter.O

Respuestas:

12

Algo como

sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less

tee cut-logle permite ver en pantalla lo que se está poniendo en el archivo cut-log.

EDITAR:

Para satisfacer los exigentes estándares de fred.bear, aquí hay una solución sed (aunque podría decirse que la solución awk es mucho más bonita):

b=BB; e=EE ;echo -e "AA\nAA\nBB\nBB\nCC\nCC\nDD\nDD\nEE\nEE\nFF\nFF" | sed -n ":b;/$b/b p;n;b b;:p;p;n;/$e/b e;b p;:e;p;n;/$e/b e;q"
asoundmove
fuente
3
@ Dogbane: sí, sí. Editado Estoy seguro de que a veces escribes un código menos que óptimo, ¿merece un comentario tan duro?
asoundmove
1
nota: Si hay varias líneas consecutivas de 'primera fecha' con la misma fecha, todas menos la primera no se eliminarán y se introducirán en la salida ... solo algo a tener en cuenta ... (depende de la situación)
Peter
1
... pero, aunque soy un pro-sed ++, creo que este trabajo en particular está más allá de sus límites, para cualquier otra cosa que no sea una herramienta personal propia. Aquí está el problema principal que sed tiene en este caso (el suyo y mío ... logré que sed hiciera lo mismo que el tuyo ... también funcionó dentro del 1%) ... volviendo al problema principal ... (que no se aplica a awk) ... Error (no reparable): Con respecto a una fecha que sea válida dentro del alcance del registro, pero que no esté realmente presente en el registro, en el caso del primer argumento, causará que sed no imprima nada, y en el caso del segundo argumento, imprimirá todo después de la primera cita! ... más ...
Peter.O
1
Otro error corregible: es que actualmente coincide con las fechas en cualquier línea, incluido el protión de datos, pero eso es solo un ajuste de expresiones regulares. Y para cualquiera que quiera usarlo, tal vez podría comentar que los argumentos ahora se refieren al primero y últimas fechas en el rango (no -1 y +1) ... y finalmente ... mis "estándares exigentes" no son míos. Yo sólo soy el mensajero de la solicitud interrogadores ... El usuario va a notar si funciona conforme a lo solicitado, o no .. Esto ha sido un gran problema para mí .. He aprendido mucho :) ... y me alegro saber que sedpuede igualar la awkvelocidad, y en realidad fue un poco más rápido.
Peter.O
6

Para imprimir todo entre FOO y BAR inclusive, intente:

$ sed -n '/FOO/,/BAR/p' file.txt
dogbane
fuente
1
nota: Esto solo imprimirá el primer BAR de una serie de BARES consecutivos ...
Peter.O
otra nota ... Gran problema si alguna de las fechas no está presente en los datos. Si la última fecha no está presente, sed seguirá generando líneas hasta que llegue a EOF.
Peter.O
5

Esto hará lo que desee ...
Se muestran las fechas de parámetros incluidos y excluidos.

# set Test args
set  2011-02-24  2011-02-26  "junk"

from="$1"
till="$2"
file="$3"

# EITHER ====                              +++++++++  
# Ouptut lines between two parameter dates INCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 >= from) && ($2 <= till) { print $0 ; next }
    ($2 > till) { exit }' "$file"

# OR ========                              ---------
# Ouptut lines between two parameter dates EXCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 > from) && ($2 < till) { print $0 ; next }
    ($2 >= till) { exit }' "$file"

Prueba una fecha (ordenada) en el campo 2 ... Aquí hay un ejemplo de los datos de prueba

    98  2011-02-05 xxxx
    99  2011-02-05 xxxx
   100  2011-02-06 xxxx
   101  2011-02-06 xxxx

Y aquí está el generador de datos de prueba .

Peter.O
fuente
Lo escribiría (tomando el primero, por ejemplo) un poco más simplemente así: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove
@asoundmove: Sí, eso puede verse mejor, y definitivamente es más convencional , pero en realidad, su tiempo de ejecución es solo la duración de 1 ifdeclaración adicional en total (ni siquiera 1 por línea), es decir. el flujo lógico es efectivamente el mismo, y la diferencia en el tiempo de ejecución se contaría en nanosegundos ... La única razón por la que no usé "else" es que este es efectivamente mi primer awkscript (aparte de un día 4 años Hace cuando jugué con algunos ejemplos) ... y ese es el primer mecanismo de bifurcación funcional que encontré ... (y como se mencionó. Es igual de rápido). Generalmente uso sedTryq
Peter
No entiendo dónde le das el nombre del archivo de texto y la ubicación en este método. alguien puede ayudarme a ver a través de mi estupidez
Giles
4

Si en su archivo de registro tiene las fechas en este formato YYYY-MM-DD, entonces, para encontrar todas las entradas para decir, 2011-02-10, puede hacer:

grep 2011-02-10 log_file

Ahora, digamos, si desea encontrar las entradas para 2011-02-10 y 2011-02-11, entonces, nuevamente use greppero con múltiples patrones:

grep -E '2011-02-10|2011-02-11' log_file
Barun
fuente
Bueno. Funciona "como se anuncia" :) ... Sin embargo, grepbuscará todo el archivo, incluso si el intervalo de fechas se encuentra al comienzo del archivo. En promedio, esto duplica el tiempo de una búsqueda, en comparación con "exit-after-last-item-in-range" ... Solo me molesto en mencionar esto debido al tamaño de archivo de 8 GB mencionado en la pregunta, Su Los resultados del tiempo grep son casi idénticos al ejemplo sed aquí (1min 58sec). Aquí está el enlace a los resultados de mis pruebas de tiempo: paste.ubuntu.com/573477
Peter.O
1

Trabajar con este tamaño de archivos siempre es difícil.

Un camino a seguir podría ser dividir este archivo en un par de pequeños, para hacer esto puede usar el comando dividir.

split -d -l 50000 ToBigFile.data file_

Incluso si está dividido, aún puede trabajar con el archivo como si fuera uno que usa un bash for loop

for f in `ls file_*`; do cat $f; done;

Pero en lugar del gato puede usar grep invertido para deshacerse de los datos no deseados, eso es irrelevante para esto. (o el tipo de refinamiento que necesita).

En este punto, solo trabajará con muchos archivos más pequeños, y los comandos que los otros mencionados anteriormente funcionarán de manera más suave en muchos archivos más pequeños.

Y cuando haya terminado, puede usar un segundo bucle for para construir nuevamente el nuevo archivo más pequeño.

for f in `ls file_*`; do cat $f >> NewFile.data ; done;

Actualización Dado que comenzamos a dividir los datos en varios archivos, va a haber mucho trabajo con el disco duro y eso lleva tiempo. (En esta pregunta aparentemente 5min).

Por otro lado, los próximos pasos probablemente serían más rápidos.

Por lo tanto, este método probablemente no tiene sentido para la operación simple grep, awk, sed, pero si los patrones de búsqueda se vuelven más complicados, podría volverse más rápido.

Johan
fuente
3
Johanm, toma un tiempo awk y sed solo 1 minuto, en promedio, para buscar un archivo de registro de 8 GB en mi computadora, y en el mismo equipo, solo la división del archivo inicial, toma 4min 43sec ... :)
Peter.O
Digamos que podría reducir esos tiempos awk y sed en un 50% en los archivos más pequeños. Entonces todavía tenemos que hacer algo más que 10 de los que la operación antes de que ganamos en el tiempo total ... Así que tal vez la división del archivo no es la mejor idea para un par de regresiones ...
Johan
El script awk podría (fácilmente) modificarse para generar 10 resultados de búsqueda diferentes en 10 archivos ... en una sola pasada, pero eso ralentizaría la lectura mientras en realidad generaba los informes ... Sed también podría hacer lo mismo, pero como yo Como mencioné en los comentarios de asoundmove, sed fallará si una fecha / hora en particular no tiene entrada en el registro (por ejemplo, está buscando por hora). Uso sed mucho y es extremadamente útil, pero tiene sus límites. ... Aquí hay un FAQ de sed sobre cuándo usar sed vs awk ... No estoy necesariamente de acuerdo con todo eso, pero puedo ver lo que significan ... sed.sourceforge.net/sedfaq6.html
Peter. O
0
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file
puente de Charles
fuente
Sin embargo, esto solo imprimirá la primera entrada de registro para el 25/02/2011.
Gilles 'SO- deja de ser malvado'