Wie schneide ich ein Teil aus einer Protokolldatei?

18

Ich habe eine 8-GB-Protokolldatei (Rails-Produktionsprotokoll). Ich muss es zwischen einigen Daten (Linien) schneiden. Welchen Befehl könnte ich verwenden, um dies zu tun?

Eric Leschinski
quelle
1
Hey Leute, bei dieser Frage geht es um eine große Datei, also ist es "Ante up!". Auf die Zeit kommt es an. Ich habe das bevorzugte sed-Skript an einer echten 8-GB-Datei mit 85904064 Zeilen (100 Zeichen pro Zeile) getestet. Ich liebe sed, aber so wie es aussieht, scannt das sed-Skript jedes Mal die gesamte Datei . Dies macht es im Durchschnitt doppelt so langsam wie das awk-Skript, das beim Auffinden beendet wird. Ich denke (?), Dass das sed-Skript für den zweiten Ausdruck möglicherweise nur aq anstelle von d benötigt. Die Testergebnisse sind hier: paste .ubuntu.com / 573477 .. Außerdem erzeugt es nicht die richtige Ausgabe .. siehe meinen Kommentar am Ende der Antwort von asoundmove.
Peter.O
Die neue sed-Version von asoundmove hatte das Geschwindigkeitsproblem behoben und entspricht nun der Geschwindigkeit von awks. und die neue Version gibt die Daten jetzt korrekt aus ... Weitere Informationen finden Sie in seinen Kommentaren.
Peter.O
Mir ist gerade aufgefallen, dass Sie "Ausschneiden" gesagt haben (was normalerweise "Entfernen" bedeutet) ... Meinen Sie wirklich "Ausschneiden" oder "Kopieren"? .... Wenn du "schneiden" gemeint hast, dann sedmachst du es leicht.
Peter.O

Antworten:

12

So etwas wie

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

tee cut-logDamit können Sie auf dem Bildschirm sehen, was in der Datei abgelegt wird cut-log.

BEARBEITEN:

Um den hohen Ansprüchen von fred.bear gerecht zu werden, hier eine sed-Lösung (obwohl die awk-Lösung wahrscheinlich viel hübscher ist):

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
quelle
3
@dogbane: Ja, ja. Bearbeitet Ich bin mir sicher, dass Sie manchmal weniger als optimalen Code schreiben. Verdient er einen so harten Kommentar?
Asoundmove
1
Hinweis: Wenn es mehrere aufeinanderfolgende Zeilen mit dem ersten Datum gibt, werden alle Zeilen bis auf die erste nicht gelöscht und in die Ausgabe eingefügt die Situation)
Peter.O
1
... aber obwohl ich ein Pro-Sed ++ bin, denke ich, dass dieser spezielle Job für etwas anderes als ein persönliches Werkzeug über seine Grenzen hinausgeht. Hier ist das Hauptproblem, das Sed in diesem Fall hat (deins und meins .. ich habe es geschafft, dasselbe zu tun wie deins .. es lief auch innerhalb von 1%) .. zurück zum Hauptproblem .. (das gilt nicht für awk) .... Fehler (nicht behebbar): Bezüglich eines Datums, das im Rahmen des Protokolls gültig ist, aber nicht tatsächlich im Protokoll vorhanden ist, wird im Fall des 1. Arg. Sed nichts drucken, und im Fall des 2. Arg. Sed wird alles gedruckt nach dem ersten date! ... mehr ...
Peter.O
1
Ein weiterer, behebbarer Fehler: Stimmt derzeit mit Daten in einer beliebigen Zeile überein, einschließlich des Datenprotions, aber das ist nur eine Regex-Optimierung. Und für alle, die es verwenden möchten, könnten Sie vielleicht kommentieren, dass sich die Argumente jetzt auf das erste und das letzte beziehen letzte Termine im Bereich (nicht -1 und +1) .. und schließlich .. meine "hohen Standards" sind nicht meine. Ich bin nur der Bote der Anfrage der Fragesteller ... Der Benutzer wird bemerken, ob es wie gewünscht funktioniert oder nicht. Dies war eine großartige Frage für mich. Ich habe viel gelernt :) ... und ich bin froh zu wissen, das sedkann awkfür die Geschwindigkeit passen , und es war tatsächlich ein bisschen schneller.
Peter.O
6

Um alles zwischen FOO und BAR einschließlich zu drucken, versuchen Sie:

$ sed -n '/FOO/,/BAR/p' file.txt
Dogbane
quelle
1
Hinweis: Hiermit wird nur der erste BAR einer Reihe aufeinanderfolgender BARS
gedruckt
Noch ein Hinweis ... Großes Problem, wenn eines der Daten nicht in den Daten vorhanden ist. Wenn das letzte Datum nicht vorhanden ist, gibt sed so lange Zeilen aus, bis es EOF erreicht.
Peter.O
5

Dies wird tun, was Sie wollen ...
Sowohl einschließlich als auch ausschließlich der Parameterdaten werden angezeigt.

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

Es wird in Feld 2 nach einem (sortierten) Datum gesucht ... Hier ein Beispiel für die Testdaten

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

Und hier ist der Testdatengenerator .

Peter.O
quelle
Ich würde es etwas einfacher schreiben (zum Beispiel das erste Beispiel): awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove
@asoundmove: Ja, das kann aussehen besser, und es ist auf jeden Fall mehr konventionellen , aber in Wirklichkeit ist seine Ausführungszeit nur die Dauer von 1 Extra ifAussage insgesamt (nicht einmal 1 pro Zeile) , dh. Der logische Ablauf ist praktisch derselbe und die Laufzeitdifferenz wird in Nanosekunden gezählt. Der einzige Grund, warum ich kein "else" verwendet habe, ist, dass dies praktisch mein erstes awkSkript ist (abgesehen von einem Tag und vier Jahren) Vor, als ich mit einigen Beispielen gespielt habe) ... und das ist der erste funktionsfähige Verzweigungsmechanismus, den ich gefunden habe ... (und wie erwähnt. Es ist genauso schnell) .. Ich verwende generell sedTryq
Peter.O
Ich verstehe nicht, wo Sie den Namen und den Speicherort der Textdatei in dieser Methode angeben. kann mir jemand helfen, meine Dummheit zu durchschauen
Giles
4

Wenn Sie in Ihrer Protokolldatei die Daten in diesem Format haben YYYY-MM-DD, können Sie Folgendes tun, um alle Einträge beispielsweise vom 10.02.2011 zu finden:

grep 2011-02-10 log_file

Sagen wir nun, wenn Sie die Einträge für 2011-02-10 und 2011-02-11 finden möchten, dann verwenden Sie erneut, grepaber mit mehreren Mustern:

grep -E '2011-02-10|2011-02-11' log_file
Barun
quelle
Gut. Es funktioniert „wie in der Werbung“ :) ... aber grepdie gesamte Datei suchen, auch wenn das Datum Bereich am Anfang der Datei ist. Im Durchschnitt verdoppelt sich die Zeit für eine Suche im Vergleich zu "Exit-after-last-item-in-range" Die Grep-Zeit-Ergebnisse sind fast identisch mit dem hier gezeigten Sed-Beispiel (1 Min. 58 Sek.). Hier ist der Link zu meinen Zeittestergebnissen
Peter.O
1

Das Arbeiten mit dieser Dateigröße ist immer schwierig.

Sie können diese Datei auch in ein paar kleine Dateien aufteilen. Verwenden Sie hierzu den Befehl split.

split -d -l 50000 ToBigFile.data file_

Auch wenn es aufgeteilt ist, können Sie mit der Datei arbeiten, als ob Sie eine Bash for-Schleife verwenden würden

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

Anstelle der Katze können Sie jedoch auch invertiertes grep verwenden, um unerwünschte Daten zu entfernen, was für diesen Zweck irrelevant ist. (oder die Art der Verfeinerung, die Sie benötigen).

An diesem Punkt arbeiten Sie nur mit vielen kleineren Dateien, und die Befehle, die oben erwähnt wurden, funktionieren bei vielen kleineren Dateien reibungsloser.

Und wenn Sie fertig sind, können Sie eine zweite for-Schleife verwenden, um die neue kleinere Datei erneut zu erstellen.

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

Update Da wir anfangen, die Daten in mehrere Dateien aufzuteilen, wird es eine Menge Arbeit mit der Festplatte geben, und das braucht Zeit. (In dieser Frage offenbar 5min).

Andererseits wären die nächsten Schritte wahrscheinlich schneller.

Daher ist diese Methode für einfache grep-, awk- und sed-Operationen wahrscheinlich sinnlos, aber wenn die Suchmuster komplizierter werden, kann sie schneller werden.

Johan
quelle
3
Johanm, das Durchsuchen einer 8-GB-Protokolldatei auf meinem Computer dauert im Durchschnitt nur 1 Minute, und auf demselben Computer dauert das Aufteilen der ersten Datei nur 4 Minuten, 43 Sekunden ... :)
Peter.O
Nehmen wir an, Sie könnten die awk- und sed-Zeiten bei kleineren Dateien um 50% reduzieren. Dann müssen wir noch mehr als 10 dieser Operationen durchführen, bevor wir die Gesamtzeit erreichen ... Vielleicht ist die Aufteilung der Dateien nicht die beste Idee für ein paar Regressionen ...
Johan
Das awk-Skript könnte (leicht) modifiziert werden, um 10 verschiedene Suchergebnisse in 10 Dateien in einem Durchgang auszugeben, aber das würde das Lesen verlangsamen, während die Berichte tatsächlich ausgegeben werden ... Sed könnte auch dasselbe tun, aber wie ich Habe in den Kommentaren von asoundmove erwähnt, dass sed fehlschlägt, wenn für ein bestimmtes Datum / eine bestimmte Uhrzeit kein Eintrag im Protokoll vorhanden ist (z. B. Sie suchen stundenweise). Ich verwende sed häufig und es ist äußerst nützlich, aber es hat seine Grenzen ... Hier ist eine sed-FAQ zum Einsatz von sed vs awk. Ich bin nicht unbedingt einverstanden mit allem, aber ich kann sehen, was sie bedeuten ... sed.sourceforge.net/sedfaq6.html
Peter. O
0
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file
Charles-Brücke
quelle
Dadurch wird jedoch nur der erste Protokolleintrag für den 25.02.2011 gedruckt.
Gilles 'SO- hör auf böse zu sein'