Löschen Sie bestimmte Zeilennummern aus einer Textdatei mit sed?

235

Ich möchte eine oder mehrere bestimmte Zeilennummern aus einer Datei löschen. Wie würde ich das mit sed machen?

Justin Ethier
quelle
1
Können Sie ein genaueres Beispiel dafür geben, was Sie wollen? Wie werden Sie entscheiden, welche Zeilen entfernt werden sollen?
Mark Byers
Vielleicht siehe auch stackoverflow.com/questions/13272717/… und nur umgekehrt anwenden (drucken, wenn Schlüssel nicht im assoziativen Array).
Tripleee

Antworten:

373

Wenn Sie die Zeilen 5 bis 10 und 12 löschen möchten:

sed -e '5,10d;12d' file

Dadurch werden die Ergebnisse auf dem Bildschirm gedruckt. Wenn Sie die Ergebnisse in derselben Datei speichern möchten:

sed -i.bak -e '5,10d;12d' file

Dadurch wird die Datei gesichert file.bakund die angegebenen Zeilen gelöscht.

Hinweis: Zeilennummern beginnen bei 1. Die erste Zeile der Datei ist 1, nicht 0.

Brian Campbell
quelle
31
Nicht alle Unixe haben mit "-i" gnu sediert. Machen Sie nicht den Fehler, auf "sed cmd file> file" zurückzugreifen, wodurch Ihre Datei gelöscht wird.
Pra
4
Was wäre, wenn ich die 5. Zeile bis zur letzten Zeile löschen wollte?
Jürgen Paul
14
@WearetheWorldsed -e '5,$d' file
Brian Campbell
1
@BrianCampbell Was soll ich tun, um nur eine bestimmte Zeile zu löschen?
Kanagavelu Sugumar
14
@ KanagaveluSugumar sed -e '5d' file. Die Syntax lautet <address><command>; Dabei <address>kann es sich entweder um eine einzelne Zeile 5oder um einen Zeilenbereich handeln 5,10, und der Befehl dlöscht die angegebene Zeile oder die angegebenen Zeilen. Die Adressen können auch reguläre Ausdrücke oder das Dollarzeichen sein $, das die letzte Zeile der Datei angibt.
Brian Campbell
50

Sie können eine bestimmte einzelne Zeile mit ihrer Zeilennummer durch löschen

sed -i '33d' file

Dadurch wird die Zeile mit der Zeilennummer 33 gelöscht und die aktualisierte Datei gespeichert.

amit
quelle
1
In meinem Fall hat "sed" eine falsche Zeile entfernt. Also benutze ich diesen Ansatz : sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'. Vielen Dank!
Eduardo Lucio
Gleich hier habe ich eine Schleife geschrieben und seltsamerweise haben einige Dateien die richtige Zeile verloren, aber einige Dateien haben auch eine andere Zeile verloren, haben keine Ahnung, was schief gelaufen ist. (GNU / Linux bash4.2) awk Befehl unten funktionierte gut in Schleife
FatihSarigol
Seien Sie sehr vorsichtig, wenn Sie sort -r verwenden, wenn Sie aus einer Liste von Zeilen löschen, da sonst Ihr erstes sed die Zeilennummern von allem anderen ändert! ...
Konchog
Um zu kommentieren, dass falsche Zeilen innerhalb einer Schleife gelöscht werden:
Beginnen Sie unbedingt
25

und awk auch

awk 'NR!~/^(5|10|25)$/' file
Ghostdog74
quelle
2
NB: Diese awk-Linie funktionierte für mich zuverlässiger als die sed-Variante (zwischen OS-X und Ubuntu Linux)
Jay Taylor
3
Beachten Sie, dass dadurch nichts in der Datei gelöscht wird. Es druckt nur die Datei ohne diese Zeilen nach stdout. Sie müssen also auch die Ausgabe in eine temporäre Datei umleiten und dann die temporäre Datei verschieben, um das Original zu ersetzen.
Mivk
17
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$ 
Matthew Slattery
quelle
6

Dies ist sehr oft ein Symptom für ein Antimuster. Das Werkzeug, mit dem die Zeilennummern erstellt wurden, kann durchaus durch ein Werkzeug ersetzt werden, mit dem die Zeilen sofort gelöscht werden. Beispielsweise;

grep -nh error logfile | cut -d: -f1 | deletelines logfile

(Wo deletelinesist das Dienstprogramm, von dem Sie sich vorstellen, dass Sie es benötigen) ist dasselbe wie

grep -v error logfile

Wenn Sie sich jedoch in einer Situation befinden, in der Sie diese Aufgabe wirklich ausführen müssen, können Sie sedaus der Datei mit den Zeilennummern ein einfaches Skript erstellen. Humorvoll (aber vielleicht etwas verwirrend) kann man das damit machen sed.

sed 's%$%d%' linenumbers

Dies akzeptiert eine Datei mit Zeilennummern, eine pro Zeile, und erzeugt bei der Standardausgabe dieselben Zeilennummern, dan die jeweils eine angehängt wird. Dies ist ein gültiges sedSkript, das wir in einer Datei speichern oder (auf einigen Plattformen) an eine andere sedInstanz weiterleiten können:

sed 's%$%d%' linenumbers | sed -f - logfile

Wenn Sie auf einigen Plattformen sed -fdas Optionsargument nicht als -Standardeingabe verstehen , müssen Sie das Skript in eine temporäre Datei umleiten und es bereinigen, wenn Sie fertig sind, oder den einzelnen Bindestrich durch /dev/stdinoder durch /proc/$pid/fd/1Ihr Betriebssystem (oder Ihre Shell) ersetzen ) hat das.

Wie immer können Sie -ivor der -fOption hinzufügen , dass seddie Zieldatei bearbeitet werden soll, anstatt das Ergebnis in der Standardausgabe zu erzeugen. Auf * BSDish-Plattformen (einschließlich OSX) müssen Sie ebenfalls ein explizites Argument angeben -i. eine übliche Redewendung ist es, ein leeres Argument zu liefern; -i ''.

Tripleee
quelle
Ich bin mit dem "Symptom eines Antimusters" nicht ganz einverstanden. Markup-basierte Dateitypen (z. B. XML oder JSON) erfordern bestimmte Zeilen am Ende, um gültige Dateien zu sein. In diesem Fall ist es oft der vernünftigste Ansatz, diese Zeilen zu entfernen, in die Datei einzufügen, was hinzugefügt werden soll, und diese Zeilen dann erneut hinzuzufügen, da das sofortige Einfügen der Zeilen viel mehr Aufwand bedeuten kann und dagegen spricht der potenzielle Wunsch, zusätzliche Werkzeuge wie sed so weit wie möglich zu vermeiden.
Egor Hans
Ich verstehe nicht ganz, was für ein Szenario Sie sich vorstellen. Es gibt Szenarien, in denen dies ein legitimer Ansatz ist, aber die überwiegende Mehrheit der Fälle, die ich gesehen habe, sind Neulinge, die mehr oder weniger genau das tun, was mein erstes Beispiel zeigt. (Vielleicht kommen sie aus einer wirklich niedrigen Sprache und sind es gewohnt, ihr Problem weit über die molekulare Ebene hinaus zu teilen, weil man in asm oder C muss.)
Tripleee
Das Entfernen von Inhalten anhand der Zeilennummer aus XML oder JSON klingt äußerst spröde, wenn nicht sogar geradezu gefährlich.
Tripleee
Damit meine ich im Grunde, dass Sie als Ersteller einer solchen Datei wissen, was am Ende des Dokuments stehen muss (dh der Satz von schließenden Klammern / eckigen Klammern in den letzten Zeilen für JSON oder das genaue Tags für XML schließen). Der einfachste Ansatz zum Erweitern eines solchen Dokuments ist, 1) die letzten Zeilen zu entfernen, 2) den neuen Inhalt hinzuzufügen, 3) die letzten Zeilen erneut hinzuzufügen. Auf diese Weise kann das Dokument sowohl vor als auch nach seiner Erweiterung gültig sein, ohne dass eine Möglichkeit zum Hinzufügen von Zeilen in der Mitte des Dokuments gefunden werden muss.
Egor Hans
1
Bisher ist dies die einzige Antwort mit einer geeigneten Lösung für eine große Anzahl von Zeilen (dh von einer Datei bereitgestellt). Und das Vorwort macht auch Sinn. Es verdient mehr Gegenstimmen. Übrigens, wenn Sie Zeilen drucken möchten, anstatt sie zu löschen, verwenden Sie pstattdessen dzusammen mit der Option -n(es funktioniert nicht ohne -nund !dauch nicht).
Skippy le Grand Gourou
2

Ich möchte eine Verallgemeinerung mit awk vorschlagen.

Wenn die Datei aus Blöcken fester Größe besteht und die zu löschenden Zeilen für jeden Block wiederholt werden, kann awk auf diese Weise einwandfrei funktionieren

awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print  $0}'
 OriginFile.dat > MyOutputCuttedFile.dat

In diesem Beispiel ist die Größe für den Block 2000 und ich möchte die Zeilen [1..713] und [1026..1029] drucken.

  • NR ist die Variable, die von awk zum Speichern der aktuellen Zeilennummer verwendet wird.
  • % gibt den Rest (oder Modul) der Division von zwei ganzen Zahlen an;
  • nl=((NR-1)%BLOCKSIZE)+1Hier schreiben wir in die Variable nl die Zeilennummer innerhalb des aktuellen Blocks. (siehe unten)
  • ||und &&sind die logischen Operatoren OR und AND .
  • print $0 schreibt die ganze Zeile

Why ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
  +1   We add again 1 because we want to restore the desired order.

+-----+------+----------+------------+
| NR  | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
|  1  |  1   |    0     |     1      |
|  2  |  2   |    1     |     2      |
|  3  |  0   |    2     |     3      |
|  4  |  1   |    0     |     1      |
+-----+------+----------+------------+

Hastur
quelle
2
Ich bewundere die Art und Weise, wie Sie Ihrem verrückten Namen gerecht werden.
Jukka Dahlbom