Beim Versuch, ein Problem mit einem Server zu debuggen, besteht meine einzige Protokolldatei aus einer 20 GB-Protokolldatei (sogar ohne Zeitstempel! Warum verwenden Leute System.out.println()
als Protokollierung? In Produktion ?!)
Mit grep habe ich einen Bereich der Datei gefunden, den ich mir gerne ansehen möchte, Zeile 347340107.
Anders als etwas zu tun
head -<$LINENUM + 10> filename | tail -20
... die head
benötigt, um die ersten 347 Millionen Zeilen der Protokolldatei durchzulesen. Gibt es einen schnellen und einfachen Befehl, der die Zeilen 347340100 - 347340200 (z. B.) an die Konsole ausgeben würde?
update Ich habe total vergessen, dass grep den Kontext um ein Match herum drucken kann ... das funktioniert gut. Vielen Dank!
mit GNU-grep könnte man einfach sagen
grep --context = 10 ...
Ich habe zwei andere Lösungen gefunden wenn Sie die Zeilennummer kennen, aber sonst nichts (kein grep möglich):
Angenommen, Sie brauchen die Zeilen 20 bis 40,
sed -n '20,40p;41q' file_name
oder
awk 'FNR>=20 && FNR<=40' file_name
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3, efficient on large files
Methode 3 für große Dateien effizient
schnellste Weg, um bestimmte Zeilen anzuzeigen
Nein, das ist nicht der Fall, Dateien sind nicht zeilenadressierbar.
Es gibt keine Möglichkeit, den Anfang der Zeile n in einer Textdatei zu finden. Sie müssen durch die Datei streamen und Zeilenumbrüche zählen.
Verwenden Sie das einfachste/schnellste Werkzeug, das Sie für die Arbeit benötigen. Für mich macht die Verwendung von head
viel mehr Sinn als grep
, da letztere viel komplizierter ist. Ich sage nicht "grep
ist langsam", das ist es wirklich nicht, aber ich wäre überrascht, wenn es für diesen Fall schneller ist als head
. Das wäre im Grunde ein Fehler in head
.
Wie wäre es mit:
tail -n +347340107 filename | head -n 100
Ich habe es nicht getestet, aber ich denke, das würde funktionieren.
Ich hatte die Datei zuerst in einige kleinere aufgeteilt
$ split --lines=50000 /path/to/large/file /path/to/output/file/prefix
und dann grep auf die resultierenden Dateien.
Ich gehe lieber in less
und
:43210
, um dasselbe zu tunund solche Sachen.
Noch besser: getroffen v an dieser Stelle mit der Bearbeitung zu beginnen (natürlich in vim!). Beachten Sie nun, dass vim
die gleichen Tastenzuordnungen hat!
Sie können den Befehl ex
verwenden, einen Standard-Unix-Editor (jetzt Teil von Vim), z.
anzeige einer einzelnen Zeile (z. B. 2. Zeile):
ex +2p -scq file.txt
entsprechende sed-Syntax: sed -n '2p' file.txt
zeilenbereich (z. B. 2-5 Zeilen):
ex +2,5p -scq file.txt
sed-Syntax: sed -n '2,5p' file.txt
von der angegebenen Zeile bis zum Ende (z. B. 5. bis Ende der Datei):
ex +5,p -scq file.txt
sed-Syntax: sed -n '2,$p' file.txt
mehrere Zeilenbereiche (z. B. 2-4 und 6-8 Zeilen):
ex +2,4p +6,8p -scq file.txt
sed-Syntax: sed -n '2,4p;6,8p' file.txt
Die obigen Befehle können mit der folgenden Testdatei getestet werden:
seq 1 20 > file.txt
Erläuterung:
+
oder -c
gefolgt vom Befehl - Führen Sie den Befehl (vi/vim) aus, nachdem die Datei gelesen wurde.-s
- unbeaufsichtigter Modus, verwendet auch das aktuelle Terminal als Standardausgabe.q
gefolgt von -c
ist der Befehl zum Beenden des Editors (fügen Sie !
hinzu, um das Beenden zu erzwingen, z. B. -scq!
).sed muss auch die Daten lesen, um die Zeilen zu zählen .. Die einzige Möglichkeit, eine Verknüpfung zu erstellen, wäre Kontext/Reihenfolge in der Datei, auf der gearbeitet werden soll. Wenn beispielsweise Protokollzeilen mit einer festen Breite (Datum/Uhrzeit) usw. vorangestellt sind, können Sie das Dienstprogramm look unix verwenden, um die Dateien nach bestimmten Datumsangaben zu durchsuchen
Get ack
ack --lines = Dateiname am Anfang
Benutzen
x=`cat -n <file> | grep <match> | awk '{print $1}'`
Hier erhalten Sie die Zeilennummer, in der die Übereinstimmung stattgefunden hat.
Jetzt können Sie den folgenden Befehl verwenden, um 100 Zeilen zu drucken
awk -v var="$x" 'NR>=var && NR<=var+100{print}' <file>
oder Sie können auch "sed" verwenden
sed -n "${x},${x+100}p" <file>
Aufbauend auf der Antwort von Sklivvz ist hier eine Nice-Funktion, die in eine .bash_aliases
-Datei eingefügt werden kann. Dies ist bei großen Dateien effizient, wenn Sie Dokumente von der Vorderseite der Datei aus drucken.
function middle()
{
startidx=$1
len=$2
endidx=$(($startidx+$len))
filename=$3
awk "FNR>=${startidx} && FNR<=${endidx} { print NR\" \"\$0 }; FNR>${endidx} { print \"END HERE\"; exit }" $filename
}
Mit sed -e '1,N d; M q'
drucken Sie die Zeilen N + 1 bis M. Dies ist wahrscheinlich etwas besser als grep -C
, da es nicht versucht, die Zeilen einem Muster zuzuordnen.
Wenn Ihre Zeilennummer 100 zu lesen ist
head -100 filename | tail -1
So zeigen Sie eine Zeile aus einem <textfile>
anhand ihres <line#>
an:
Perl -wne 'print if $. == <line#>' <textfile>
Wenn Sie eine leistungsfähigere Methode zum Anzeigen einer Reihe von Zeilen mit regulären Ausdrücken wünschen, kann ich nicht sagen, warum Grep dazu eine schlechte Idee ist. Es sollte ziemlich offensichtlich sein - dieser einfache Ausdruck zeigt Ihnen Ihre Reichweite in einer Einfacher Durchgang, was Sie wollen, wenn Sie ~ 20 GB Textdateien verwenden:
Perl -wne 'print if m/<regex1>/ .. m/<regex2>/' <filename>
(Tipp: Wenn in Ihrem Regex /
enthalten ist, verwenden Sie stattdessen etwas wie m!<regex>!
)
Dies würde <filename>
ausgeben, beginnend mit der Zeile, die mit <regex1>
übereinstimmt, bis (und einschließlich) der Zeile, die mit <regex2>
übereinstimmt.
Es braucht keinen Assistenten, um zu sehen, wie einige Verbesserungen ihn noch leistungsfähiger machen können.
Das Letzte: Perl, da es sich um eine ausgereifte Sprache handelt, bietet viele verborgene Verbesserungen, um Geschwindigkeit und Leistung zu fördern. Aus diesem Grund ist es die offensichtliche Wahl für eine solche Operation, da sie ursprünglich für die Verarbeitung großer Protokolldateien, Text, Datenbanken usw. entwickelt wurde.
Einfach mit Perl! Wenn Sie die Zeilen 1, 3 und 5 aus einer Datei erhalten möchten, sagen Sie/etc/passwd:
Perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd
Sie können diesen Befehl ausprobieren:
egrep -n "*" <filename> | egrep "<line number>"
Ich bin erstaunt, dass nur eine andere Antwort (von Ramana Reddy) vorschlug, der Ausgabe Zeilennummern hinzuzufügen. Im Folgenden wird nach der gewünschten Zeilennummer gesucht und die Ausgabe wird farbig dargestellt.
file=FILE
lineno=LINENO
wb="107"; bf="30;1"; rb="101"; yb="103"
cat -n ${file} | { GREP_COLORS="se=${wb};${bf}:cx=${wb};${bf}:ms=${rb};${bf}:sl=${yb};${bf}" grep --color -C 10 "^[[:space:]]\\+${lineno}[[:space:]]"; }