Wie erfolgt die Inplace-Änderung einer Datei?

10

Was bedeutet die "Inplace" -Modifikation einer Datei, zB via sed -ioder perl -i?
Meine Frage ist, wie diese Inplace-Änderung durchgeführt wird. Wird die Datei kopiert, erfolgt die Änderung in der Kopie und ersetzt dann das Original? Oder wird die Originaldatei irgendwie geändert?

Jim
quelle
Werfen Sie einen Blick auf backreference.org/2011/01/29/in-place-editing-of-files für eine ausführliche Erklärung dieses Themas.
scy
Wie geht das eigentlich mit exoder vi?
Wildcard
@ Wildcard - jeder von ihnen hat ein ganzes System. exverwaltet eine Mail-Datei (wie dead.mailoder etwas in ~ Ihnen und eine andere in der Nähe Ihres Mail-Spoolers, normalerweise) . Überprüfen Sie die Spezifikationen - jeder von ihnen hat einen zu großen Längen definierten Status ... exhat in den meisten Fällen ein eigenes Binärformat (siehe Ihre -rescueDatei) und wird verwendet, um separate temporäre Pufferdateien (möglicherweise bis zu sechs) vor Null zu setzen . Also kopieren diese Eingabeblöcke, um Puffer zu bearbeiten und Schreibvorgänge pro Änderung in Offsets zu synchronisieren :!written?
Mikeserv

Antworten:

18

sed Erstellt eine temporäre Datei, schreibt die Ausgabe in diese Datei und benennt die temporäre Datei über dem Original um.

Sie können beobachten, was passiert, indem Sie strace:

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

Dies protokolliert alle Dateivorgänge sed: Es erstellt eine neue Datei (sicher mit O_CREAT|O_EXCL), schreibt die Daten in sie und verschiebt sie dann wieder über meine ursprüngliche Datei a.

sed -iAkzeptiert ein Suffix, das für eine Sicherung verwendet werden soll. In diesem Fall wird das Original zuerst aus dem Weg geräumt (anstatt es umzubenennen). Dieses Argument ist in den meisten BSDs obligatorisch sed. In diesem Fall gibt es eine kurze Zeit, in der sich überhaupt keine Datei mit dem richtigen Namen im Verzeichnis befindet.

perl In neueren Versionen wird die Eingabedatei geöffnet, dann gelöscht und eine neue Datei mit demselben Namen erstellt:

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

Wenn Sie unlinkeine bereits geöffnete Datei löschen ( ), behalten Sie den Zugriff darauf, solange Sie das Handle behalten, damit die Daten aus der gelöschten Datei weiter gelesen werden können. Auf diese Weise wird perldirekt in die Ausgabedatei und nicht in eine temporäre Datei geschrieben: Es wird keine zusätzliche Datei erstellt. Wenn Sie die Datei jedoch während des Vorgangs lesen, erhalten Sie im Gegensatz zum sedAnsatz von partiellen Inhalt . Es gibt auch eine kurze Zeit, in der es keine Datei mit dem richtigen Namen gibt, die sich eher am Anfang des Prozesses als am Ende befindet (wie in sed -i .bak).


Beides sedund perlwird:

  • Ersetzen Sie einen symbolischen Link durch eine normale Datei.
  • Brechen Sie harte Verbindungen.
  • Bewahren Sie nach Möglichkeit den Gruppenbesitz auf.
  • Erstellen Sie die Datei mit Ihrer Standardgruppe (oder der Gruppe des übergeordneten Verzeichnisses, wenn dieses Verzeichnis das setgidBit enthält), wenn sie einer Gruppe gehört, in der Sie sich nicht befinden, und Sie sich nicht im Stammverzeichnis befinden.
  • Behalten Sie den Dateibesitz bei, wenn Sie root sind.
  • Grundlegende Berechtigungen beibehalten.
  • Preserve setuidund setgrpBits, wenn die resultierende Gruppe mit der Gruppe übereinstimmt, in der sie gestartet wurde.
  • Bewahren Sie das klebrige Stück auf.
  • Xattrs nicht aufbewahren.

sed werden:

  • ACLs beibehalten (unter Linux; ich weiß nichts über andere) .

perl werden:

  • ACLs nicht beibehalten.

Dies gilt unter Linux mit GNU sedund Mac OS X mit (von FreeBSD abgeleitet) sed.

Michael Homer
quelle
3

Zusätzlich zu @ Homers Antwort von perldoc perlrun:

Gibt an, dass vom Konstrukt "<>" verarbeitete Dateien direkt bearbeitet werden sollen. Dazu wird die Eingabedatei umbenannt, die Ausgabedatei unter dem ursprünglichen Namen geöffnet und diese Ausgabedatei als Standard für print () -Anweisungen ausgewählt. Die Erweiterung wird, falls angegeben, verwendet, um den Namen der alten Datei zu ändern und eine Sicherungskopie gemäß den folgenden Regeln zu erstellen:

Wenn keine Erweiterung angegeben wird, wird keine Sicherung durchgeführt und die aktuelle Datei wird überschrieben.

Wenn die Erweiterung kein * enthält, wird sie als Suffix an das Ende des aktuellen Dateinamens angehängt. Wenn die Erweiterung ein oder mehrere * Zeichen enthält, wird jedes * durch den aktuellen Dateinamen ersetzt.

Und denken Sie daran, dass kein Softlink oder Hardlink erhalten bleibt:

Beachten Sie, dass weiche und harte Links im UNIX-Stil nicht beibehalten werden, da -i die Originaldatei umbenennt oder löscht, bevor eine neue Datei mit demselben Namen erstellt wird.

Schließlich behindert der Schalter -i die Ausführung nicht, wenn keine Dateien in der Befehlszeile angegeben werden. In diesem Fall wird keine Sicherung durchgeführt (die Originaldatei kann natürlich nicht ermittelt werden), und die Verarbeitung wird erwartungsgemäß von STDIN nach STDOUT fortgesetzt.

Dies erklärt auch, warum Sie -imit -pOption oder eine explizite printAnweisung verwenden müssen, wenn Sie anstelle von bearbeiten möchten perl:

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file
cuonglm
quelle