sed: löscht alle Zeilen einer Datei außer den letzten X

sed: löscht alle Zeilen einer Datei außer den letzten X

Dies kann auch mit anderen Tools durchgeführt werden, mich interessiert jedoch, wie ich mit alle Zeilen außer den letzten X-Zeilen der Datei löschen kann sed.

Antwort1

Im Grunde emulieren Sie tail. In diesem Beispiel ist x = 20. Das folgende Beispiel löscht alle Zeilen außer den letzten 20:

sed -i -e :a -e '$q;N;21,$D;ba' filename

Erläuterung:

  • Mit -e :a wird eine Bezeichnung mit dem Namen a erstellt.
  • Das nächste -e:
    • $q - beendet und druckt den Musterbereich, wenn es die letzte Zeile ist
    • N - nächste Zeile
    • 21,$D – führt den Befehl „D“ aus, wenn die Zeilennummer >= 21 ist (21,$ = 21. Zeile bis $, also das Ende der Datei)
    • ba – verzweigt zum Label „a“, das den Anfang des Skripts darstellt.

Antwort2

sedist bei Aufgaben wie dieser ziemlich komplex. tailoder grepwürde awkdies viel einfacher machen und sollte stattdessen verwendet werden. Davon abgesehen ist esIstmöglich.

Die folgende Lösung wurde angepasst vonsed und mehrzeiliges Suchen und Ersetzen.

sed -ni '
    # if the first line copy the pattern to the hold buffer
    1h
    # if not the first line then append the pattern to the hold buffer
    1!H
    # if the last line then ...
    ${
            # copy from the hold to the pattern buffer
            g
            # delete current line if it is followed by at least X more lines
            # replace X-1 with the proper value
            s/.*\n\(\(.*\n\)\{X-1\}\)/\1/
            # print
            p
    }
' filename

Ohne die Kommentare ist es ein netter Einzeiler. Wenn Sie beispielsweise alles außer den letzten zehn Zeilen entfernen möchten, verwenden Sie Folgendes:

sed -ni '1h;1!H;${;g;s/.*\n\(\(.*\n\)\{9\}\)/\1/;p;}' filename

Antwort3

Basierend auf dem Skript inAbschnitt 4.13 des sed-HandbuchsSie könnten so etwas tun:

n=10

(( n > 1 )) && script='1h; 2,'$n'{H;g;}; $q; 1,'$((n-1))'d; N; D'
(( n > 1 )) || script='$!d'

sed -i "$script" infile

Antwort4

tac|sed|tac>&&(mv||Katze>)

Beide der folgenden Befehlsausschnitte löschen effektiv alle bis auf diezuletzt5Linienvon ~/file1. Wenn Sie diezuletzt10Linien, können Sie ersetzen: |sed '1,5!d;'durch |sed '1,10!d;',und so weiter, wie Sie es für richtig halten.

  1. tac ~/"file1" |sed '1,5!d;' |tac >"/tmp/file2" &&mv  "/tmp/file2"  ~/"file1"
  2. tac ~/"file1" |sed '1,5!d;' |tac >"/tmp/file2" &&cat "/tmp/file2" >~/"file1"

verwandte Informationen