bash - parameter - sed substitute




Wie kann ich die erste Zeile einer Textdatei mit dem bash/sed Skript entfernen? (9)

Da es sich anhört, als könnte ich die Löschung nicht beschleunigen, denke ich, dass ein guter Ansatz darin besteht, die Datei in Stapeln zu verarbeiten:

While file1 not empty
  file2 = head -n1000 file1
  process file2
  sed -i -e "1000d" file1
end

Der Nachteil davon ist, dass, wenn das Programm in der Mitte getotet wird (oder wenn da etwas schlechtes sql drin ist - was dazu führt, dass das "Prozess" -Teil stirbt oder sich aufhängt), Linien, die entweder übersprungen oder zweimal verarbeitet werden .

(Datei1 enthält Zeilen von SQL-Code)

Ich muss wiederholt die erste Zeile aus einer riesigen Textdatei mit einem Bash-Skript entfernen.

Im Moment verwende ich sed -i -e "1d" $FILE - aber es dauert etwa eine Minute, um das Löschen zu machen.

Gibt es einen effizienteren Weg, dies zu erreichen?


Für diejenigen, die auf SunOS sind, was nicht GNU ist, wird der folgende Code helfen:

sed '1d' test.dat > tmp.dat 

Nein, das ist ungefähr so ​​effizient, wie du bekommen wirst. Sie könnten ein C-Programm schreiben, das den Job ein wenig schneller erledigen könnte (weniger Startzeit und Verarbeitungsargumente), aber es wird wahrscheinlich die gleiche Geschwindigkeit wie sed haben, wenn Dateien groß werden (und ich nehme an, sie sind groß, wenn es eine Minute dauert) ).

Aber Ihre Frage leidet unter dem gleichen Problem wie so viele andere, dass sie die Lösung voraussetzt. Wenn Sie uns im Detail mitteilen würden, was Sie anstatt wie zu tun versuchen, können wir vielleicht eine bessere Option vorschlagen.

Wenn dies beispielsweise eine Datei A ist, die ein anderes Programm B verarbeitet, wäre eine Lösung, die erste Zeile nicht zu entfernen, sondern das Programm B zu modifizieren, um es anders zu verarbeiten.

Angenommen, alle Ihre Programme hängen an diese Datei A an, und Programm B liest und verarbeitet die erste Zeile, bevor sie gelöscht wird.

Sie könnten Programm B neu konstruieren, so dass es nicht versucht hat, die erste Zeile zu löschen, sondern einen permanenten (wahrscheinlich dateibasierten) Offset in der Datei A beibehält, damit es beim nächsten Mal nach diesem Offset-Prozess suchen kann die Zeile dort, und aktualisieren Sie den Offset.

Dann könnte es zu einer ruhigen Zeit (Mitternacht?) Eine spezielle Verarbeitung von Datei A durchführen, um alle gerade verarbeiteten Zeilen zu löschen und den Versatz zurück auf 0 zu setzen.

Es wird sicherlich schneller sein, wenn ein Programm eine Datei öffnet und sucht, anstatt sie zu öffnen und neu zu schreiben. Diese Diskussion setzt natürlich voraus, dass Sie Kontrolle über Programm B haben. Ich weiß nicht, ob das der Fall ist, aber es kann andere mögliche Lösungen geben, wenn Sie weitere Informationen bereitstellen.


Probieren Sie GNU Tail aus :

tail -n +2 "$FILE"

-nx : Einfach die letzten x Zeilen drucken. tail -n 5 würde Ihnen die letzten 5 Zeilen der Eingabe geben. Das + -Zeichen invertiert das Argument und macht tail Print alles andere als die ersten x-1 Zeilen. tail -n +1 würde die gesamte Datei tail -n +2 , tail -n +2 alles außer der ersten Zeile usw.

GNU tail ist viel schneller als sed . tail ist auch auf BSD verfügbar und das Flag -n +2 ist in beiden Tools konsistent. Weitere Informationen finden Sie in den FreeBSD oder OS X- Manpages.

Die BSD-Version kann jedoch viel langsamer als sed . Ich frage mich, wie sie das geschafft haben; tail sollte nur eine Datei Zeile für Zeile lesen, während sed ziemlich komplexe Operationen ausführt, die das Interpretieren eines Skripts, das Anwenden regulärer Ausdrücke und dergleichen umfassen.

Hinweis: Sie könnten versucht sein zu verwenden

# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"

aber das wird dir eine leere Datei geben . Der Grund ist, dass die Umleitung ( > ) vor dem Aufruf des Tails durch die Shell erfolgt:

  1. Shell schneidet die Datei $FILE
  2. Shell erstellt einen neuen Prozess für den tail
  3. Shell leitet stdout des tail Prozesses zu $FILE
  4. tail liest aus der nun leeren $FILE

Wenn Sie die erste Zeile in der Datei entfernen möchten, sollten Sie Folgendes verwenden:

tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"

Das && sicher, dass die Datei bei einem Problem nicht überschrieben wird.


Sie können -i verwenden, um die Datei zu aktualisieren, ohne den Operator '>' zu verwenden. Der folgende Befehl löscht die erste Zeile aus der Datei und speichert sie in der Datei.

sed -i '1d' filename

Würden Sie Tail auf N-1-Zeilen verwenden und diese in eine Datei leiten, gefolgt von dem Entfernen der alten Datei und dem Umbenennen der neuen Datei in den alten Namen?

Wenn ich dies programmatisch durchführe, würde ich die Datei durchlesen und mich nach dem Lesen jeder Zeile an den Dateioffset erinnern, so dass ich mich an diese Position begeben könnte, um die Datei mit einer Zeile weniger darin zu lesen.


Wie Pax sagte, wirst du wahrscheinlich nicht schneller werden. Der Grund dafür ist, dass es fast keine Dateisysteme gibt, die das Abschneiden vom Anfang der Datei unterstützen, so dass dies eine O ( n ) -Operation ist, wobei n die Größe der Datei ist. Was Sie jedoch viel schneller machen können, ist die erste Zeile mit der gleichen Anzahl von Bytes zu überschreiben (vielleicht mit Leerzeichen oder einem Kommentar), die für Sie funktionieren könnte, abhängig davon, was genau Sie versuchen (was ist das übrigens?).


Wie wäre es mit csplit?

man csplit
csplit -k file 1 '{1}'

Sponge vermeidet das Jonglieren einer temporären Datei:

tail -n +2 "$FILE" | sponge "$FILE"




sed