Drucken Sie nur eindeutige Zeilen, die basierend auf Datum/Uhrzeit zuletzt in der Protokolldatei erscheinen

Drucken Sie nur eindeutige Zeilen, die basierend auf Datum/Uhrzeit zuletzt in der Protokolldatei erscheinen

Ich arbeite mit einer Protokolldatei mit folgendem Format:

Oct 12 01:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 01:30:00 server program: 192.168.1.104 text for 1.104 
Oct 12 01:30:23 server program: 192.168.1.103 text for 1.103
Oct 12 01:32:39 server program: 192.168.1.101 text for 1.101 
Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103 
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101 

Ich muss dies erreichen:

Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101

Wie kann ich die neue Ausgabe in eine Datei senden? Ich habe Folgendes versucht:

awk '!_[$6]++ {a=$6} END{print a}' logfile

Aber es liefert mir nicht die erwarteten Ergebnisse. Wie kann ich awk oder sed verwenden, um mir nur die eindeutigen Zeilen mit dem letzten Zeitpunkt der Zeichenfolgenübereinstimmung oder basierend auf Datum/Uhrzeit anzuzeigen?

Antwort1

Wenn Sie einen zweiten Durchgang durchführen (was so ziemlich notwendig ist), können Sie auch nur Zeilennummern statt vollständiger Datensätze speichern. Das macht die Logik einfacher.

awk 'NR == FNR {if (z[$6]) y[z[$6]]; z[$6] = FNR; next} !(FNR in y)' logfile logfile

Richtigkeitsnachweis:

Am Ende der Verarbeitung jeder Zeile wird jede bisher verarbeitete Zeilennummerentwederein Wert in z,oderein Index (kein Wert) in y, aber nie beides.

Die durch die Werte in dargestellten Zeilen zstellen am Ende jeder Iteration genau und nur die neuesten Datensätze dar, die bisher für jede IP-Adresse angezeigt wurden.

Die Indizes von ysind also genau die Linien, die wirnichtzu drucken.

Antwort2

Speichern Sie die gesamte Zeile (unter Verwendung $6als Array-Index) und ENDiterieren Sie über die Elemente des Arrays:

awk '{z[$6]=$0};END{for (i in z) print z[i]}' logfile

Das Ergebnis wird jedoch nicht sortiert. Sie könnten beispielsweise Folgendes tun:

awk '{z[$6]=NR" "$0};END{for (i in z) print z[i]}' logfile | sort -k1,1n | cut -f2-
### this space ^ is a literal TAB

Dadurch wird die Zeilennummer sowie der Zeileninhalt gespeichert, um anschließend nach der Zeilennummer sortieren zu können.


Bei anderen Methoden ist ein zweiter Durchgang erforderlich, um die Sortierung nach Datum zu erhalten (da es sich um ein Protokoll handelt), es werden jedoch doppelte Einträge gedruckt, wenn die Eingabe doppelte Zeilen enthält (also ganze Zeilen), z. B. mit grep:

awk '{z[$6]=$0};END{for (var in z) print z[var]}' logfile | grep -Fxf- logfile

oder nur mit awk:

awk 'NR==FNR{z[$6]=$0;next}
FNR==1{for (var in z) y[z[var]]}
$0 in y' logfile logfile

Antwort3

Wenn Sie nur Zeilen vom selben Tag haben, können Sie dies folgendermaßen handhaben:

sort -k6 -k3r logfile | uniq -f3 | sort -k3

Wenn Sie Zeilen für mehr als einen Tag haben, können Sie diesen grundlegenden Ansatz trotzdem verwenden, aber Ihre Sortierung muss dann viel ausgefeilter werden. Der obige Befehl kann nur die Datensätze eines Tages verarbeiten, da er den Zeitanteil des Zeitstempels (z. B. 02:28:26) als Proxy für den gesamten Zeitstempel verwendet.

Antwort4

Die Logik wird einfacher, wenn die Datei zeilenweise umgekehrt wird

$ tac logfile | awk '!seen[$6]++' | tac
Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103 
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101 

verwandte Informationen