it-swarm.com.de

Schneller Unix-Befehl zur Anzeige bestimmter Zeilen in der Mitte einer Datei?

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!

165
matt b

mit GNU-grep könnte man einfach sagen 

grep --context = 10 ...
66
Mathias Weidner

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
344
Sklivvz
# 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

99
WCC

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.

23
unwind

Wie wäre es mit:

tail -n +347340107 filename | head -n 100

Ich habe es nicht getestet, aber ich denke, das würde funktionieren.

19
itsmatt

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.

12
Luka Marinko

Ich gehe lieber in less und

  • tippen 5% zur Hälfte der Datei gehen,
  • 43210G um zur Linie 43210 zu gelangen
  • :43210, um dasselbe zu tun

und 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!

11
sehe

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!).
8
kenorb

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

4
pixelbeat

Get ack

ack --lines = Dateiname am Anfang

3
Odeyin

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>
3
Ramana Reddy

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
}
2
Keithel

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.

2
mweerden

Wenn Ihre Zeilennummer 100 zu lesen ist 

head -100 filename | tail -1
2
Roopa

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.

0
osirisgothra

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
0
dagelf

Sie können diesen Befehl ausprobieren: 

egrep -n "*" <filename> | egrep "<line number>"
0
Fritz Dodoo

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:]]"; }
0
eel ghEEz