reanudar la lectura de un archivo de registro desde el punto en que lo dejé la última vez

reanudar la lectura de un archivo de registro desde el punto en que lo dejé la última vez

Tengo un archivo de registro que se actualiza continuamente (se agregó una nueva línea) después de un período de tiempo.

Solo obtengo mensajes de error del archivo cada 10 minutos.

Inicialmente, la primera vez busqué todas las líneas en un nuevo archivo con un patrón coincidente "ERROR ENCONTRADO" usandoawk.

Pero después de 10 minutos se agregó una línea nueva a un archivo de registro, por lo que quiero leer ese archivo de registro donde lo dejé. No quiero volver a empezar desde el principio.

¿Alguien puede sugerirme el mejor código o script para esto?

Respuesta1

Si abre el archivo en un descriptor de archivo como:

exec 3< /path/to/log/file

Luego podrás procesarlo:

awk '...' <&3

Después de lo cual fd 3 señalará donde awklo dejó.

10 minutos más tarde, desde la misma invocación de shell, puedes ejecutar eso

awk '...' <&3

comando nuevamente para procesar los nuevos datos.

Si desea guardar la posición en la que se encontraba, para poder reanudar la lectura desde una invocación de shell diferente, con ksh93, puede hacer:

#! /usr/bin/env ksh93
file=/path/to/some-file
offset_file=$file.offset

exec 3< "$file"
[ -f "$offset_file" ] && exec 3<#(($(<"$offset_file")))

awk '...' <&3

echo "$(3<#((CUR)))" > "$offset_file"

O con zsh:

#! /usr/bin/env zsh

zmodload zsh/system
file=/path/to/some-file
offset_file=$file.offset

exec 3< $file
[ -f "$offset_file" ] && sysseek -u 3 "$(<$offset_file)"

awk '...' <&3

echo $((systell(3))) > $offset_file

Respuesta2

Me gusta la respuesta de Stéphane porque no lee el archivo completo una y otra vez, así que agrego aquí elintento(en Linux) equivalente a su solución (bash no tiene ninguna función incorporada seekni tellcapacidad). Habría usado un comentario pero mi reputación es demasiado baja.

LASTPOS=/tmp/saved_pos

exec 3< "$1"
test -f "$LASTPOS" && STARTPOS=$(($(<$LASTPOS)+1))
tail -c "+${STARTPOS:-1}" <&3 | grep "ERROR FOUND"
grep '^pos:' /proc/self/fdinfo/3 | cut -f2 > "$LASTPOS"

También reemplacé el awkcomando con grepporque suele ser más rápido. Puede canalizar la salida a un awkcomando si necesita más procesamiento.

Respuesta3

Lo intentaría con wc -ly tail.
Si estás usando bash, esto debería funcionar:

#!/bin/bash
LASTLNFILE=/tmp/lastline     # replace with a suitable path
test -f $LASTLNFILE && LASTLN=$(<$LASTLNFILE)
CURLN=$(wc -l $1 | cut -d' ' -f1)

if ((CURLN-LASTLN > 0)); then
  tail -n $((CURLN-LASTLN)) $1
fi
echo $CURLN > $LASTLNFILE

PD: úselo como filtro antes de su programa awk, por ejemplo (suponiendo que lo haya llamado 'newlines.sh'):

./newlines.sh <log_file> | awk -f <your_awk_program>`

Dejo el script anterior como ejemplo de cómono lo hagas. Justo después de escribirlo, me di cuenta de que es vulnerable a una condición de carrera, siempre que el archivo de registro se actualiza mientras se ejecuta el script.

Es preferible un enfoque AWK puro:

#!/bin/awk

BEGIN { 
  lastlinefile = "/tmp/lastlinefile"
  getline lastline < lastlinefile
}

NR > lastline && /ERROR FOUND/ {
  # do your stuff...
  print
}

END { print NR > lastlinefile }

información relacionada