Wie entferne ich bestimmte Zeilen (unter Verwendung von Zeilennummern) in einer Datei?

27

Es gibt bestimmte Zeilen, die ich aus einer Datei entfernen möchte. Nehmen wir an, es ist Zeile 20-37 und dann Zeile 45. Wie würde ich das tun, ohne den Inhalt dieser Zeilen anzugeben?

Tshepang
quelle
Wie groß ist deine Akte? Könnte es in den Speicher geladen werden?
Faheem Mitha
Ein paar Kilobyte.
Tshepang

Antworten:

29

Mit sed, wie so:

sed '20,37d; 45d' < input.txt > output.txt

Wenn Sie dies vor Ort tun wollten:

sed --in-place '20,37d; 45d' file.txt
pdo
quelle
Gibt es eine Möglichkeit, dies vor Ort zu tun?
Tshepang
Ich schlage vor, sed -i Datei
Enzotib
1
@Tshepang: Use edoder GNU sed -ioder spongeoder eine Methode mit großen Dateien .
Gilles 'SO- hör auf böse zu sein'
3
Ich habe mich oft über den möglicherweise irreführenden Begriff in-place gewundert , als ich auf „sed“ Bezug nahm. Deshalb habe ich ihn in „man sed“ nachgeschlagen : --in-place [= SUFFIX]This option specifies that files are to be edited in-place. GNU sed 'erstellt dazu eine temporäre Datei und die Ausgabe an diese Datei anstatt an die Standardausgabe senden. "... Ich kenne kein anderes" sed ", aber die Logistik des Aktualisierens" an Ort und Stelle "mit einem Stream- Editor" berechnet "nicht :)
Peter.O
2
Die meisten "In-Place" -Methoden verwenden meiner Erfahrung nach eine temporäre Datei.
Faheem Mitha
5

Wenn die Datei bequem in den Speicher passt, könnten Sie auch verwenden ed.
Die Befehle sind denen oben sehr ähnlich, sedmit einem bemerkenswerten Unterschied : Sie müssen die Liste der zu löschenden Zeilennummern / -bereiche in absteigender Reihenfolge (von der höchsten Zeilennummer / -bereich bis zur niedrigsten) übergeben. Der Grund dafür ist, dass beim Löschen / Einfügen / Teilen / Verbinden von Zeilen mit edder Textpuffer nach jedem Unterbefehl aktualisiert wird. Wenn Sie also einige Zeilen löschen, befinden sich die restlichen folgenden Zeilen nicht mehr an derselben Position im Puffer, wenn die nächster Unterbefehl wird ausgeführt. Sie müssen also rückwärts beginnen 1 .
In-Place- Bearbeitung:

ed -s in_file <<IN
45d
20,37d
w
q
IN

oder

ed -s in_file <<< $'45d\n20,37d\nw\nq\n'

oder

printf '%s\n' 45d 20,37d w q | ed -s in_file

Ersetzen Sie write durch ,print, wenn Sie die resultierende Ausgabe drucken möchten, anstatt in eine Datei zu schreiben. Wenn Sie die ursprüngliche Datei beibehalten und in eine andere Datei schreiben möchten, können Sie den neuen Dateinamen an den wUnterbefehl rite übergeben:

ed -s in_file <<IN
78,86d
65d
51d
20,37d
w out_file
q
IN

1 Sofern Sie nicht bereit sind, die neuen Zeilennummern nach jedem dElete zu berechnen , was für diesen speziellen Fall ziemlich trivial ist (nach dem Löschen der Zeilen 20-37, dh 18 Zeilen, wird Zeile 45 zu Zeile 27), können Sie Folgendes ausführen:

ed -s in_file <<IN
20,37d
27d
w
q
IN

Wenn Sie jedoch mehrere Zeilennummern / -bereiche löschen müssen, ist das Rückwärtsarbeiten ein Kinderspiel.

don_crissti
quelle
Ist der qBefehl am Ende nützlich? Ich denke, es geht so oder so.
Tom Fenech
@TomFenech - nicht alle Implementierungen werden in beide Richtungen beendet (obwohl die meisten dies tun ... Ich kann den Thread, in dem dies besprochen wurde, nicht mehr finden ...)
don_crissti
1

Lies es einfach in den Speicher, ändere es und schreibe es zurück. Sie können so etwas tun

filename = "foo"
f = open(filename, 'r+')                                                                                                                                 
linenums = [1, 3]                                                                                                                                            
s = [y for x, y in enumerate(f) if x not in [line-1 for line in linenums]]                                                                                                                                          
f.seek(0)
f.write(''.join(s))
f.truncate(f.tell())
f.close()

Getestet mit einer 5-zeiligen Datei. Danksagung für http://pleac.sourceforge.net/pleac_python/fileaccess.html , siehe Abschnitt "Ändern einer Datei ohne temporäre Datei". Siehe auch https://stackoverflow.com/questions/125703/how-do-i-modify-a-text-file-in-python

Einige Notizen:

  1. Man könnte die Datei zuerst abschneiden, dann darauf schreiben, anstatt wie oben beschrieben zu schreiben und dann abzuschneiden. Ich kenne jedoch kein Python-Flag, mit dem man lesen und dann einen abgeschnittenen Schreibvorgang ausführen kann. Aber vielleicht fehlt mir etwas, da das Dokument nicht so klar ist. Welches bringt mich zu

  2. Manchmal saugen die Python-Dokumente wirklich. Siehe http://docs.python.org/library/functions.html#open

    Die Modi 'r +', 'w +' und 'a +' öffnen die Datei zum Aktualisieren (beachten Sie, dass 'w +' die Datei abschneidet).

    Bedeutet das etwas für Sie? Was zum Teufel ist "offen für Updates"?

  3. Ich weiß nicht, ob es besser ist, dies in Python zu tun, als in etwas Unixigem wie dem Stream-Editor. Es ist vielleicht portabler, aber ich weiß nicht, wie portabel sed ist. Ich habe es einfach so geschrieben, weil ich mit Low-Level-Programmierung besser zurechtkomme als mit klassischen Unix-Tools, die gut sind, wenn sie genau das tun, was Sie wollen, aber (glaube ich) im Allgemeinen weniger flexibel sind.

  4. Dieser Ansatz (Manipulieren der Datei im Speicher) tauscht Speicher gegen Speicherplatz. Es sollte auf Computern mit ein paar GB Arbeitsspeicher für Dateien bis zu ein paar hundert MB funktionieren. Python verarbeitet Zeichenfolgen nicht sehr effizient. Ein Wechsel zu C / C ++ beispielsweise würde die Leistung geringfügig verbessern und die Speichernutzung erheblich verringern.

Faheem Mitha
quelle
0

Sie können Vim im Ex-Modus verwenden:

ex -sc '20,37d|45d|x' file
  1. d löschen

  2. x speichern und schließen

Steven Penny
quelle