So verwenden Sie sed, um die letzten n Zeilen einer Datei zu entfernen

148

Ich möchte einige n Zeilen vom Ende einer Datei entfernen . Kann das mit sed gemacht werden?

Zum Beispiel, um Zeilen von 2 bis 4 zu entfernen, kann ich verwenden

$ sed '2,4d' file

Aber ich kenne die Zeilennummern nicht. Ich kann die letzte Zeile mit löschen

$sed $d file

aber ich möchte wissen, wie man n Zeilen vom Ende entfernt. Bitte lassen Sie mich wissen, wie das mit sed oder einer anderen Methode gemacht wird.

Mezda
quelle
2
@arashkordi: Dies verwendet eine Zeilenanzahl von oben in der Datei, nicht von unten.
Ams
Verwandte Frage zu Superusern .
Thor
//, Vielleicht überlegen Sie, die Frage neu zu formulieren, um sie allgemeiner zu gestalten als nur sed ?
Nathan Basanese
1
sed $d filegibt einen Fehler zurück. Stattdessen sollte $ d in Anführungszeichen wie sed '$d' file
folgt stehen

Antworten:

221

Ich weiß nicht sed, aber es kann getan werden mit head:

head -n -2 myfile.txt
ams
quelle
19
+1 der Einfachheit halber. Der entsprechende sed-Befehl ist hintern hässlich: sed -e :a -e '$d;N;2,5ba' -e 'P;D' file( ,5für die letzten 5 Zeilen).
Marc B
62
Beachten Sie, dass dies mit einigen Versionen von funktioniert head, aber nicht Standard ist. In der Tat der Standard für headStaaten:The application shall ensure that the number option-argument is a positive decimal integer.
William Pursell
21
So fügen Sie die Antwort von @ WilliamPursell hinzu ... Unter der Standard-Shell von Mac OS funktioniert dies nicht.
JDS
7
Noch auf BSD, aber die Frage ist Linux getaggt.
Ams
3
minus 1, weil dies zusätzlich zu osx bei Ubuntu14 nicht funktioniert -head: illegal line count -- -2
Michael Durrant
30

Wenn die Hardcodierung von n eine Option ist, können Sie sequenzielle Aufrufe von sed verwenden. Um beispielsweise die letzten drei Zeilen zu löschen, löschen Sie die letzte Zeile dreimal:

sed '$d' file | sed '$d' | sed '$d'
Kyle
quelle
2
Dies, plus -i, um die Datei an Ort und Stelle zu bearbeiten, anstatt sie auf stdout zu speichern, hat bei mir funktioniert.
WAF
27

Von den sed Einzeiler :

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

Scheint das zu sein, wonach du suchst.

qstebom
quelle
@Thor können Sie ändern, wie viele Zeilen aus der Datei entfernt werden, indem Sie die 10in'$d;N;2,10ba'
Alexej Magura
1
@AlexejMagura: Ich habe eine frühere Version der Antwort kommentiert.
Thor
22

Eine lustige und einfache sedund tacLösung:

n=4
tac file.txt | sed "1,$n{d}" | tac

HINWEIS

  • "Für die Shell sind doppelte Anführungszeichen erforderlich, um die $nVariable im sedBefehl auszuwerten . In einfachen Anführungszeichen wird keine Interpolation durchgeführt.
  • tacist eine catumgekehrte, sieheman 1 tac
  • die {}in sedsind da, um $n& zu trennen d(wenn nicht, versucht die Shell, nicht existierende $ndVariablen zu interpolieren )
Gilles Quenot
quelle
7
fyi no tacon osx
Michael Durrant
1
@ MichaelDurrant port info coreutils|| brew info coreutils;;
Stimmen
19

Verwenden Sie sed, aber lassen Sie die Shell rechnen, mit dem Ziel, den dBefehl zu verwenden, indem Sie einen Bereich angeben (um die letzten 23 Zeilen zu entfernen):

sed -i "$(($(wc -l < file)-22)),\$d" file

So entfernen Sie die letzten 3 Zeilen von innen nach außen:

$(wc -l < file)

Gibt die Anzahl der Zeilen der Datei an: sagen wir 2196

Wir wollen die letzten 23 Zeilen entfernen, also für die linke Seite oder den Bereich:

$((2196-22))

Gives: 2174 Somit lautet das ursprüngliche Sed nach der Shell-Interpretation:

sed -i '2174,$d' file

Mit -ider Inplace-Bearbeitung hat die Datei jetzt 2173 Zeilen!

Wenn Sie es in einer neuen Datei speichern möchten, lautet der Code:

sed -i '2174,$d' file > outputfile
lzc
quelle
15

Sie könnten Kopf dafür verwenden.

Verwenden

$ head --lines=-N file > new_file

Dabei ist N die Anzahl der Zeilen, die Sie aus der Datei entfernen möchten.

Der Inhalt der Originaldatei abzüglich der letzten N Zeilen befindet sich jetzt in new_file

Richard
quelle
8

Der Vollständigkeit halber möchte ich meine Lösung hinzufügen. Am Ende habe ich das mit dem Standard gemacht ed:

ed -s sometextfile <<< $'-2,$d\nwq'

Dies löscht die letzten 2 Zeilen in-Place - Bearbeitung mit (auch wenn es nicht eine temporäre Datei in verwenden /tmp!!)

Michel
quelle
5

Um sehr große Dateien wirklich direkt abzuschneiden, haben wir den truncateBefehl. Es weiß nichts über Zeilen, aber tail+ wckann Zeilen in Bytes konvertieren:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

Es gibt eine offensichtliche Racebedingung, wenn die Datei gleichzeitig geschrieben wird. In diesem Fall ist es möglicherweise besser zu verwenden head- es zählt die Bytes ab dem Dateianfang (Mind Disk IO), sodass wir immer an der Zeilengrenze abschneiden (möglicherweise mehr Zeilen als erwartet, wenn die Datei aktiv geschrieben wird):

truncate -s $(head -n -$lines $file | wc -c) $file

Praktischer Einzeiler, wenn Sie sich nicht anmelden können. Versuchen Sie, anstelle des Benutzernamens ein Passwort einzugeben:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure
Kamil Christus
quelle
4

Dies könnte für Sie funktionieren (GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file
Potong
quelle
Nett. Sie haben das Endapostroph ( ') verpasst .
Thor
Entschuldigung für den so späten Kommentar, aber ich versuche es und (angepasst für meine AIX / Posix) es ist fehlgeschlagen, alle bis auf die letzte Zeile zu drucken. Lesen Sie den Code, verstehe ich nicht , wie die letzten vier Zeilen entfernt werden, ist die explizite Schleife auf 4 ersten Zeilen , so dass es sicherlich Schleife nach einem d, Doder Pmit GNU sed und nicht auf Posix - Version. Scheint, als würden Zeilen nach dem nicht gedruckt Dund bleiben für eine neue Schleife im Arbeitspuffer, ohne zum "Ende" der Aktionszeile zu gelangen.
NeronLeVelu
@NeronLeVelu Das Programm liest ein Fenster mit 4 Zeilen in den Musterbereich ein, hängt dann die nächste Zeile an und druckt die erste bis zum Ende der Datei, wo die verbleibenden Zeilen gelöscht werden.
Potong
@potong ja, ich teste auf einem GNU sed und es hält den Puffer zwischen den Zeilen, in denen posix ihn entlädt, nachdem Dder gegenteilige Effekt erzielt wurde .
NeronLeVelu
4

Die meisten der oben genannten Antworten scheinen GNU-Befehle / -Erweiterungen zu erfordern:

    $ head -n -2 myfile.txt
    -2: Badly formed number

Für eine etwas tragbarere Lösung:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

ODER

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

ODER

     awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'

Wobei "10" "n" ist.

Dunkles Herz
quelle
2

Mit den Antworten hier hätten Sie bereits gelernt, dass sed nicht das beste Werkzeug für diese Anwendung ist.

Ich denke jedoch, dass es eine Möglichkeit gibt, dies mit sed zu tun. Die Idee ist, N Zeilen anzuhängen, um Platz zu halten, bis Sie lesen können, ohne EOF zu treffen. Wenn EOF gedrückt wird, drucken Sie den Inhalt des Haltebereichs und beenden Sie ihn.

sed -e '$!{N;N;N;N;N;N;H;}' -e x

Mit dem obigen Befehl sed werden die letzten 5 Zeilen weggelassen.

Rishabh Sagar
quelle
2

Versuchen Sie den folgenden Befehl:

n = line number
tail -r file_name | sed '1,nd' | tail -r
Rishav Kaushal
quelle
Bitte erläutern Sie, wie dies funktioniert. Zu Ihrer Information - um Shell-Variablen zu initialisieren, sollten wir kein Leerzeichen haben =.
Codeforester
@codeforester Die erste Zeile war ein Kommentar, denke ich. Er verwendet nur dort, tail -rwo andere die Zeilenreihenfolge tacumgekehrt haben, und macht die letzten nZeilen zu den nersten Zeilen.
Nicolas Melay
2

Dies kann in 3 Schritten erfolgen:

a) Zählen Sie die Anzahl der Zeilen in der Datei, die Sie bearbeiten möchten:

 n=`cat myfile |wc -l`

b) Subtrahieren Sie von dieser Zahl die Anzahl der zu löschenden Zeilen:

 x=$((n-3))

c) Sagen Sie sed, dass es $xbis zum Ende von dieser Zeilennummer ( ) löschen soll :

 sed "$x,\$d" myfile
Rey Lefebvre
quelle
Schlechte Mathematik. Wenn Sie 3 Zeilen löschen müssen, subtrahieren Sie 3, aber ADD 1. Wenn die Datei 10 Zeilen enthält, ist 10 - 3 = 7 und Sie verwenden sed, um die Zeilen 7 bis 10 zu löschen, dh 4 Zeilen, nicht 3.
Mathguy
1

Sie können die Gesamtzahl der Zeilen mit wc -l <file>und verwenden

head -n <total lines - lines to remove> <file>

SWW13
quelle
1

Dadurch werden die letzten 3 Zeilen entfernt von file:

for i in $(seq 1 3); do sed -i '$d' file; done;

user5780554
quelle
1
Dies ist für große Dateien viel zu teuer - die gesamte Datei muss n-mal gelesen und neu geschrieben werden! Und so viele Gabeln für sed.
Codeforester
Dies ist zwar möglicherweise nicht die effizienteste Lösung, aber bei weitem die einfachste und verständlichste
Dharam,
0

Ich bevorzuge diese Lösung;

head -$(gcalctool -s $(cat file | wc -l)-N) file

Dabei ist N die Anzahl der zu entfernenden Zeilen.

p014k
quelle
0
sed -n ':pre
1,4 {N;b pre
    }
:cycle
$!{P;N;D;b cycle
  }' YourFile

Posix-Version

NeronLeVelu
quelle
0

So löschen Sie die letzten 4 Zeilen:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   
mstafreshi
quelle
ein bisschen schwer (vor allem in Ressourcen) im Vergleich zu einem Kopf. Zumindest, tac file | sed '1,4d' | tacweil das Sortieren und Entfernen des Präfixes viele Ressourcen kostet.
NeronLeVelu
@NeronLeVelu Sie haben Recht, aber es gibt keinen tacBefehl für einige Systeme (zum Beispiel FreeBSD?)
mstafreshi
0

Ich habe mir das ausgedacht, wobei n die Anzahl der Zeilen ist, die Sie löschen möchten:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

Es ist ein kleiner Kreisverkehr, aber ich denke, es ist leicht zu folgen.

  1. Zählen Sie die Anzahl der Zeilen in der Hauptdatei hoch
  2. Subtrahieren Sie die Anzahl der Zeilen, die Sie von der Zählung entfernen möchten
  3. Drucken Sie die Anzahl der Zeilen aus, die Sie behalten und in einer temporären Datei speichern möchten
  4. Ersetzen Sie die Hauptdatei durch die temporäre Datei
  5. Entfernen Sie die temporäre Datei
coyotetechy
quelle
0

Zum Löschen der letzten N Zeilen einer Datei können Sie dasselbe Konzept von verwenden

$ sed '2,4d' file

Sie können eine Kombination mit dem Befehl tail verwenden, um die Datei umzukehren: wenn N 5 ist

$ tail -r file | sed '1,5d' file | tail -r > file

Und dieser Weg läuft auch dort, wo der head -n -5 fileBefehl nicht läuft (wie auf einem Mac!).

Alessandra Bilardi
quelle
-1

Dadurch werden die letzten 12 Zeilen entfernt

sed -n -e :a -e '1,10!{P;N;D;};N;ba'
R. Kumar
quelle
1
Eine kleine Erklärung würde bitte helfen.
Richard Wiseman