das Lesen einer Protokolldatei an der Stelle fortsetzen, an der ich es das letzte Mal verlassen habe

das Lesen einer Protokolldatei an der Stelle fortsetzen, an der ich es das letzte Mal verlassen habe

Ich habe eine Protokolldatei, die nach einigen Zeiträumen kontinuierlich aktualisiert wird (neue Zeile hinzugefügt).

Ich hole alle 10 Minuten nur Fehlermeldungen aus der Datei.

Zunächst habe ich beim ersten Mal alle Zeilen in eine neue Datei mit dem passenden Muster "FEHLER GEFUNDEN" geholt, indem ichawk.

Aber nach 10 Minuten wurde einer Protokolldatei eine weitere neue Zeile hinzugefügt, daher möchte ich die Protokolldatei dort lesen, wo ich aufgehört habe. Ich möchte nicht wieder von vorne beginnen.

Kann mir jemand den besten Code oder das beste Skript hierfür vorschlagen?

Antwort1

Wenn Sie die Datei mit einem Dateideskriptor wie diesem öffnen:

exec 3< /path/to/log/file

Anschließend können Sie es weiterverarbeiten:

awk '...' <&3

Danach zeigt fd3 dorthin, wo awkes verlassen wurde.

10 Minuten später können Sie aus demselben Shell-Aufruf heraus das folgende ausführen:

awk '...' <&3

Geben Sie den Befehl erneut ein, um die neuen Daten zu verarbeiten.

Wenn Sie die vorherige Position speichern möchten, damit Sie das Lesen von einem anderen Shell-Aufruf aus fortsetzen können, ksh93haben Sie mit folgende Möglichkeiten:

#! /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"

Oder mit 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

Antwort2

Ich mag Stéphanes Antwort, weil sie nicht immer wieder die ganze Datei liest, also füge ich hier dieSchlag(unter Linux) Äquivalent seiner Lösung (Bash hat keine integrierte Funktion seekoder tellFähigkeit). Ich hätte einen Kommentar verwendet, aber mein Ruf ist zu gering.

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"

Ich habe den awkBefehl auch durch ersetzt grep, da dies normalerweise schneller ist. Sie können die Ausgabe an einen awkBefehl weiterleiten, wenn Sie eine weitere Verarbeitung benötigen.

Antwort3

wc -lIch würde es mit und versuchen tail.
Wenn Sie Bash verwenden, sollte dies funktionieren:

#!/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

PS: Verwenden Sie es als Filter vor Ihrem Awk-Programm, zB (vorausgesetzt, Sie haben es „newlines.sh“ genannt):

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

Ich lasse das obige Skript als Beispiel stehen, wie mantu es nicht. Gleich nachdem ich es geschrieben hatte, wurde mir klar, dass es anfällig für einen Race Condition ist, wenn die Protokolldatei aktualisiert wird, während das Skript ausgeführt wird.

Ein reiner AWK-Ansatz ist vorzuziehen:

#!/bin/awk

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

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

END { print NR > lastlinefile }

verwandte Informationen