Ich muss mehrere Protokolldateien durchsuchen (alle Dateien, die in den letzten 24 Stunden erstellt wurden und alle im selben Verzeichnis gespeichert sind), um das letzte Vorkommen einer Zeichenfolge zu finden. Dies ist der Befehl, den ich geschrieben habe:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
Dies gibt jedoch nur die letzte Zeile für eine Datei zurück. Irgendwelche Vorschläge, wie man dies optimiert, um alle Zeilen zu erhalten?
bash
shell-script
text-processing
grep
Lokesh
quelle
quelle
Antworten:
Vorausgesetzt, GNU-Einrichtungen:
quelle
find
Befehle für Dateien mit ausführen-exec
. Mitbash -c
bash
find
tac .. | grep -m1 fileprefix
-d" "
mit Schnitt verwenden. Doppelte Anführungszeichen anstelle von einfachenfind
Befehl kann nach dem Dateipräfix filtern. dasgrep
sollte dafür nicht gebraucht werden. Es ist auch überraschend, dass die Suchzeichenfolge in dieser Antwort nicht enthalten ist.Wenn sich alles in einem einzigen Verzeichnis befindet, können Sie Folgendes tun:
Wenn es sich um große Dateien handelt, kann es sinnvoll sein, die Daten zu beschleunigen, indem Sie
tac
die Datei in umgekehrter Reihenfolge drucken (letzte Zeile zuerst) und danngrep -m1
mit dem ersten Vorkommen übereinstimmen. Auf diese Weise müssen Sie nicht die gesamte Datei lesen:Beide gehen davon aus, dass keine übereinstimmenden Verzeichnisse vorhanden sind
fileprefix
. Wenn dies der Fall ist, wird ein Fehler angezeigt, den Sie einfach ignorieren können. Wenn dies ein Problem ist, suchen Sie nur nach Dateien:Wenn Sie auch den Dateinamen drucken möchten, fügen Sie ihn
-H
jedemgrep
Aufruf hinzu. Oder, wenn Siegrep
es nicht unterstützen, sagen Sie ihm, dass er auch durchsuchen soll/dev/null
. Das ändert nichts an der Ausgabe, aber dagrep
mehrere Dateien angegeben sind, wird immer der Dateiname für jeden Treffer gedruckt:quelle
tac
. Es wird beendet, sobald das erste Spiel gefunden wurde. Ich habe gerade mit einer 832M-Textdatei und einem Muster in der letzten Zeile getestet.grep -m 1 pattern file
Werkzeug ~ 7 Sekunden undtac file | grep -m1 pattern
dauerte0.009
.... funktioniert, wenn Sie eine GNU haben
sed
, die die-s
Option eparate files und ein POSIX unterstütztfind
.Sie sollten jedoch wahrscheinlich die
! -type d
oder-type f
Qualifikationsmerkmale hinzufügen , da der Versuch, ein Verzeichnis zu lesen, nicht sehr nützlich ist und eine weitere Einschränkung des Bereichs auf reguläre Dateien verhindern könnte, dass ein Lesevorgang an einer Pipe- oder seriellen Gerätedatei hängt.Die Logik ist unglaublich einfach: Sie
sed
überschreibt denh
alten Speicherplatz mit einer Kopie einer übereinstimmenden Eingabezeilesearchstring
undd
löscht dann alle Eingabezeilen bis auf die letzte für jede Eingabedatei aus der Ausgabe. Wenn es zur letzten Zeile gelangt,x
ändert es seine Halte- und Musterbereiche. Wenn alsosearchstring
beim Lesen der Datei überhaupt etwas gefunden wurde, wird das letzte derartige Ereignis automatisch zur Ausgabe gedruckt, andernfalls wird eine leere Zeile geschrieben. (fügen Sie/./!d
an das Ende dessed
Skripts , wenn das nicht erwünscht ist) .Dies führt einen einzelnen
sed
Aufruf pro 65.000 Eingabedateien aus - oder was auch immer IhrARG_MAX
Limit ist. Dies sollte eine sehr performante Lösung sein und ist ganz einfach zu implementieren.Wenn Sie auch die Dateinamen mit einer aktuellen GNU möchten,
sed
können Sie sie mit demF
Befehl in separate Zeilen schreiben oder siefind
in einer separaten Liste pro Stapel drucken lassen, indem Sie den-print
primären nachher anhängen+
.quelle
Wie wäre es mit:
Das Obige gibt Ihnen eine schöne Ausgabe mit dem letzten Auftreten einer Suchzeichenfolge in jeder Datei, gefolgt vom jeweiligen Dateinamen nach dem Komma (ändern Sie den Teil ", $ 1" unter "Echo", um die Formatierung zu ändern, oder entfernen Sie ihn, falls erforderlich). Die Beispielausgabe, die in Dateien mit dem Präfix "Dateiname" nach der Suchzeichenfolge "10" sucht, lautet wie folgt:
quelle
Dies nutzt GNU
grep
‚s-H
und-n
Optionen immer sowohl die Dateinamen und die Zeilennummer aller Spiele drucken, dann sortiert es durch die Dateinamen und Zeilennummer, und Rohre es in awk, das speichert das letzte Spiel für jeden Dateinamen in einem Array, und schließlich druckt es.Eine ziemlich Brute-Force-Methode, aber sie funktioniert.
quelle