Gegenteil von tail: alle Zeilen mit Ausnahme der letzten n Zeilen


35

Wie kann ich die letzten n Zeilen einer Datei mit einem Unix-Befehlszeilenfilter verwerfen?

Das wäre ungefähr das Gegenteil von tail: tailwirft die ersten n Zeilen weg, leitet aber den Rest durch, aber ich möchte, dass der Befehl alles mit Ausnahme der letzten n Zeilen durchleitet.

Leider habe ich so etwas nicht gefunden - headhilft auch nicht. EDIT : Zumindest in Solaris werden keine negativen Argumente akzeptiert.

Update: Ich bin hauptsächlich an einer Lösung interessiert, die für große Dateien funktioniert, dh für Protokolldateien, bei denen Sie möglicherweise überprüfen möchten, was in den letzten Minuten geschehen ist.


Zu Ihrer Information bei Verwendung von head: Wenn Sie '-' vor die Zahl mit der Option -n setzen, werden alle Zeilen der einzelnen Dateien gedruckt, jedoch nicht die letzten N Zeilen (siehe unten).
G Koe

Antworten:


37

Wenn Sie GNU haben head, können Sie verwenden

head -n -5 file.txt

um alle bis auf die letzten 5 Zeilen von zu drucken file.txt.

Wenn Sie head -nkeine negativen Argumente annehmen, versuchen Sie es

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt

11
(und bete, dass file.txtdas mindestens sechs Zeilen lang ist ...)
ein Lebenslauf am

1
Leider funktioniert diese Nicht-GNU-Version auch nicht mit Streams
Armand

1
@ MichaelKjörling Zumindest auf Ubuntu ist das kein Problem. Wenn die Dateien weniger Zeilen als in angegeben enthalten head, wird eine leere Ausgabe ohne Fehler zurückgegeben.
Alphaaa

Wenn ich mich nicht irre, druckt head -n 5 die ersten 5 Zeilen, nicht alle außer den letzten 5 ...
pypmannetjies

8
head file.txt               # first 10 lines
tail file.txt               # last 10 lines
head -n 20 file.txt         # first 20 lines
tail -n 20 file.txt         # last 20 lines
head -20 file.txt           # first 20 lines
tail -20 file.txt           # last 20 lines
head -n -5 file.txt         # all lines except the 5 last
tail -n +5 file.txt         # all lines except the 4 first, starts at line 5

1
Was bedeutet dies, das in der akzeptierten Antwort nicht beantwortet wurde? Ebenso wie bei Ihren anderen Antworten würden ein paar Erklärungen zu Ihrer Antwort diese erheblich verbessern.
music2myear

1
sehr gute zusammenfassung
ruanhao

5

Hier ist eine einfache Möglichkeit, die letzte Zeile zu löschen, die unter BSD usw. funktioniert.

sed '$d' input.txt

Der Ausdruck lautet "in der letzten Zeile löschen". Die anderen Zeilen werden gedruckt, da dies das sedStandardverhalten ist.

Sie können sie verketten, um mehrere Zeilen zu entfernen

sed '$d' input.txt | sed '$d' | sed '$d'

Das ist zwar etwas unbeholfen, durchsucht die Datei aber nur einmal.

Sie können auch einen Blick darauf werfen, um weitere Antworten zu erhalten: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Hier ist ein Einzeiler, angepasst von einem meiner Favoriten:

N=10
sed -n -e ':a' -e "1,$N!{P;N;D;};N;ba"

Es hat mir Spaß gemacht, dieses zu entziffern, und ich hoffe, dass Sie es auch tun (: Es puffert NZeilen beim Scannen, aber ansonsten ist es ziemlich effizient.


3

Ich bin neugierig, warum Sie denken, headist keine Option:

~$ man head
...
-n, --lines=[-]K
        print the first K lines instead of the first 10; 
        with the leading `-', print all but the last K lines of each file

Dies scheint zu Ihrem Zweck zu passen, zum Beispiel mit:

head -n -20 yourfile.txt

5
Beachten Sie, dass dies nur für GNU gilt head. BSD headdiese Option nicht hat, so dass diese Antwort wird nicht ohne GNU coreutils auf Solaris oder anderen Unix - Varianten arbeiten. Das OP hat dies auch speziell mit Unix und Unix-Utils versehen.
Slhck

2
@slhck Ganz zu schweigen von der Tatsache, dass das OP erwähnt hat, dass dies für Solaris ist.
einen Lebenslauf vom

Leider hat jemand meine Erwähnung von Solaris entfernt. Aber ich hätte trotzdem erwähnen sollen, dass die Version von head das nicht unterstützt.
Hans-Peter Störr

1
Entschuldigung an alle. Ich habe weder Solaris bemerkt, noch war ich mir der verschiedenen Versionen von head bewusst.
Anders R. Bystrup

1
@ hstoerr Solaris ist jetzt in Ihren Tags :)
slhck

0

Eine andere Möglichkeit, dies zu tun, wenn tail -nkeine negativen Argumente verwendet werden, ist

tac file.txt | tail -n +6 | tac

Dies würde die letzten 5 Zeilen entfernen


Vielen Dank! Das ist eine clevere Idee, die sich bisher noch niemand ausgedacht hat. Leider wäre das für den Anwendungsfall, den ich bei dieser Frage hatte, ziemlich ineffizient: Wenn es sich um eine große Datei handelt, wird sie nicht nur ein- oder mehrmals vollständig durchgelesen, wie bei den anderen Lösungen, sondern wahrscheinlich auch beschrieben Festplatte zu temporären Dateien von TAC, wenn es nicht in den Speicher passt.
Hans-Peter Störr

@ Hans-Peter Sehr wahr. Beschlossen, ein Python3-Skript dafür zu schreiben. Versuchen Sie dieses github.com/atw31337/donkey . Ich empfehle die Ausgabeoptionen. Sie werden viel schneller ausgeführt als Weiterleitungen.
atw31337

Schön geschrieben! Die Datei wird jedoch zweimal durchgelesen. Dies ist nicht unbedingt erforderlich, wenn Sie die letzten n Zeilen puffern. Dies ist ein Problem bei großen Dateien. Persönlich brauche ich das nicht mehr, aber für den Fall, dass Sie Spaß daran haben, es zu verbessern und andere Leute das brauchen ... Es gab schließlich ein paar Likes und Bookmarks zu dieser Frage.
Hans-Peter Störr

@ Hans-Peter. Die Puffergröße hängt von der Anzahl der zu entfernenden Zeilen ab. Dies kann ein Problem sein, wenn eine sehr große Anzahl von Zeilen aus der Datei entfernt werden muss. Um Speicherprobleme zu vermeiden, habe ich das Skript umgeschrieben und die Zeilenzählmethode mit hohen n-Werten und eine Puffermethode mit niedrigeren n-Werten verwendet. Nach dem Testen in einer sehr großen Datei ist die ursprüngliche Zeilenzählmethode jedoch immer noch schneller. Der Aufwand für die Pufferverwaltung überwiegt anscheinend den Aufwand für die Zeilenanzahl ... oder ich vermisse nur etwas.
atw31337

Nizza, aber für BSD-Variante Mac OS X gibt es standardmäßig keinen tac-Befehl. :( Diese Art von besiegt den Anwendungsfall.
Ingyhere
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.