Wie kann ich mit grep / sed in einer großen Textdatei Text aus verschiedenen Datumsbereichen abrufen?

9

Ich habe großen Dateitext (fast 3 GB) - es ist eine Protokolldatei. Ich möchte Textzeilen aus dieser Datei vom 13. bis 19. Juli erhalten, die einer Reihe von Daten entsprechen. Mein Protokollformat ist:

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>

also nach grep/ sedsollte es wie folgt ausgegeben werden:

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

Wie kann ich das bekommen?

Corey
quelle
2
Bist du sicher, dass du Juni meinst ? Alle Daten in Ihrer Beispielprotokolldatei liegen im Juli, und das gewünschte Ausgabebeispiel impliziert, dass Sie letzteres gemeint haben.
David Foerster

Antworten:

13

Mit grepwenn Sie die Anzahl der Zeilen wissen wollen , Sie Kontext - Option verwenden können -AZeilen nach dem Muster drucken

grep -A 3 2016-07-13 file

Das gibt Ihnen die Zeile mit 2013-07-13 und den nächsten 3 Zeilen

Mit können sedSie die Daten verwenden, um so abzugrenzen

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

Hiermit werden alle Zeilen von der ersten Zeile bis zum 13.07.2016 bis einschließlich der ersten Zeile bis zum 19.07.2016 gedruckt. Dies setzt jedoch voraus, dass Sie mit dem 19.07.2016 nur eine Zeile haben (die nächste Zeile wird nicht gedruckt). Wenn mehrere Zeilen vorhanden sind, verwenden Sie stattdessen das nächste Datum und dlöschen Sie die Ausgabe daraus

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

Dieser einfache Grep One Liner wird ausreichen:

grep -E ^2016-07-1[3-9] filename

Funktioniert hier gut und es besteht keine Notwendigkeit für sed :)

Verweise:

andrew.46
quelle
1
Wie immer bringst du Gnade :)
Zanna
(y) ... musste entfernen ^, damit es funktioniert. Mac verwenden.
Anum Sheraz
4

awk Lösung:

$ 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> 

Grundsätzlich wird jede Zeile von der beginnenden 2016-07-13bis zur beginnenden Zeile gedruckt2016-07-19

Sergiy Kolodyazhnyy
quelle
4

Alle anderen aktuellen Antworten beruhen auf der Tatsache, dass die Protokolldateieinträge chronologisch sortiert sind oder dass der Datumsbereich leicht mit regulären Ausdrücken abgeglichen werden kann. Wenn Sie eine allgemeinere Lösung wünschen, müssen wir etwas mehr programmieren.

Ich präsentiere dieses GNU AWK-Skript:

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

Sie geben die Start- und Endzeit über die Variablen starttimeund endtimein einem Format an, das mktimeversteht ( YYYY MM DD hh dd ss). Daher führen Sie den awkBefehl wie folgt aus, vorausgesetzt, das obige Awk-Skript befindet sich in einer ausführbaren Datei filter-log-dates.awkim aktuellen Arbeitsverzeichnis und die Protokolldatei lautet mylog.txt:

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

Beachten Sie, dass die Endzeit exklusiv ist , dh gültige Protokollsätze müssen vor der Endzeit einen Zeitstempel haben.

Wenn Ihr Zeitstempelformat anders ist, können Sie den an die matchFunktion übergebenen regulären Ausdruck entsprechend anpassen .

David Foerster
quelle
3

Sie könnten es in Schritten tun. Suchen Sie die Nummer der ersten Zeile, die Ihrem Startmuster entspricht. Suchen Sie die Nummer der letzten Zeile, die Ihrem Endmuster entspricht. Extrahieren Sie dann den Test zwischen diesen beiden Zeilen. Dies kann wie folgt erfolgen.

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

Dies kann alles in einem awkBefehl erfolgen, aber die Schritte können das Befolgen erleichtern. Innerhalb von awk ist die NR-Variable die aktuelle Zeilennummer. Da nach dem Muster keine Aktion angegeben wurde (NR> = 1234 && NR <= 5678), werden standardmäßig die Zeilen gedruckt, die sich in diesem Bereich befinden.

Jeffrey Ross
quelle