Entfernen der ersten N Zeilen einer Datei in der unix-Kommandozeile
Ich versuche zu entfernen, die ersten 37 Zeilen aus einer sehr, sehr großen Datei. Ich habe den Versuch gestartet, sed und awk, aber Sie scheinen zu verlangen, das kopieren der Daten in eine neue Datei. Ich bin auf der Suche nach einem "entfernen von Zeilen in-place" - Methode, dass im Gegensatz zu sed -i
ist nicht die Herstellung von Kopien jeder Art, sondern ist nur das entfernen von Zeilen aus der alten Datei.
Hier ist, was ich getan habe...
awk 'NR > 37' file.xml > 'f2.xml'
sed -i '1,37d' file.xml
Beide scheinen, um eine vollständige Kopie. Gibt es irgendeine andere einfache Befehlszeilenschnittstelle, die dies tun können schnell ohne ein vollständiges Dokument-traversal?
- Beide
sed -i
undgawk v4.1 -i -inplace
Optionen sind grundsätzlich erzeugen der temporären Datei hinter die kulissen. IMOsed
werden sollte, der schneller alstail
undawk
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es gibt keinen einfachen Weg, das zu tun inplace-editing mit der UNIX-Dienstprogramme, aber hier ist ein inplace-Datei-Modifikation, die Lösung, die Sie vielleicht in der Lage sein, zu ändern, für Sie zu arbeiten (mit freundlicher Genehmigung von Robert Bonomi an https://groups.google.com/forum/#!topic/comp.unix.shell/5PRRZIP0v64):
Die Letzte Datei sollte
$count
bytes kleiner als das original (da das Ziel war, zu entfernen$count
bytes von Anfang an), also zu beenden, müssen wir entfernen die letzten$count
bytes. Wir sind mitconv=notrunc
oben, um sicherzustellen, dass die Datei nicht vollständig entleert, anstatt Sie einfach abgeschnitten (siehe Beispiel unten). Auf einem GNU-system wie Linux zu tun das abschneiden danach kann erreicht werden durch:Zum Beispiel zu löschen, werden die ersten 5 Zeilen aus dieser 12-Linien-Datei
Ersten Verwendung
dd
zu entfernen Sie die Ziel-5 Linien (wirklich "$Byte," Byte) von dem Beginn der Datei, und kopieren den rest vom Ende nach vorne, aber lassen Sie das nachgestellte "$bytes" bytes ist:und verwenden Sie dann
truncate
zu entfernen, die übrig gebliebenen bytes vom Ende:Hätten wir versucht, die oben ohne
dd ... conv=notrunc
:Finden Sie in der google groups thread von mir verwiesen wird, für andere Vorschläge und info.
conv=notrunc
imdd
, andernfalls schlägt der Befehl fehl.+1
.#!/bin/bash file=enwiki-latest-pages-articles.xml count=`head -37 "$file" |wc -c` dd if="$file" bs="$count" skip=1 of="$file" conv=notrunc
^C1223734+0 records in 1223734+0 records out 2902697048 bytes (2.9 GB) copied, 59.699 s, 48.6 MB/s
Jedoch, meine Daten /Optik/ feine. Kann ich Vertrauen, Ihre Integrität aus, dass man es ab? Es scheint nicht, wie 2,9 GB benötigt, um kopiert werden, für 37 kurze Zeilen von Daten.$count
bytes vom Ende der Datei, wenn Sie fertig sind. Ich habe bearbeitet Ihre Antwort, um dies zu berücksichtigen, damit künftige Leser eine umfassende Lösung.truncate
entfernt Letzte n bytes, wenn die angegebene Größe kleiner ist als die tatsächliche Dateigröße, während die Frage über das erste n Zeilendd
entfernt die ersten N-bytes lässt aber N bytes im Wert von unerwünschtem text am Ende der Datei, so dass Sie dann verwenden wirtruncate
zu entfernen, die unerwünschte nachfolgende text. Ich habe gerade aktualisiert die Frage zeigen ein komplettes Beispiel.Unix-file-Semantik nicht zulassen und abschneiden des vorderen Teils einer Datei.
Alle Lösungen werden entweder basierend auf:
ed
,ex
andere Editoren). Dies sollte in Ordnung sein, wenn Sie Ihre Datei <1GB oder wenn Sie viel RAM.sed -i
,awk
/tail > foo
). Das ist in Ordnung, solange Sie genügend freien Festplattenspeicher für die Kopie, und nichts dagegen zu warten.Wenn die Datei zu groß für eine dieser arbeiten für Sie, können Sie in der Lage sein, das zu umgehen, je nachdem, was Lesen Sie Ihre Datei.
Vielleicht Ihre Leser überspringt die Kommentare oder leere Zeilen? Wenn dem so ist, dann können Sie Handwerk eine Nachricht, die der Leser ignoriert, stellen Sie sicher, es hat die gleiche Anzahl von bytes wie der 37 ersten Zeilen in Ihrer Datei, und überschreiben Sie den start der Datei mit
dd if=yourdata of=file conv=notrunc
.bunzip2 filename.xml.bz2 | awk 'NR > 37' filename.xml
ed ist der standard-editor:
$ time ed -s ff <<< $'1,37d\nwq' real 0m0.251s user 0m0.219s sys 0m0.032s $ time sed -i '1,37d' ff real 0m1.415s user 0m0.399s sys 0m1.016s
:)
noch, es könnte schneller sein als sed oder awk...Wird die Kopie angelegt werden müssen, irgendwann - warum nicht an der Zeit zu Lesen, das "geändert" - Datei, streaming-die veränderte Kopie anstatt es zu speichern?
Was ich mir denke - eine named pipe erstellen "Datei2" das ist die Ausgabe, die gleichen awk 'NR > 37' file.xml oder was auch immer, dann liest wer Datei2 nicht sehen, die ersten 37 Zeilen.
Der Nachteil ist, dass es laufen wird, awk jedes mal, wenn die Datei bearbeitet wird, so dass es machbar ist nur, wenn es die Lesen nur selten.