Ein Freund von mir weist darauf hin, dass, wenn Sie dies tun:
perl -pi.bak -e 's/foo/bar/' somefile
Wenn "somefile" tatsächlich ein Symlink ist, macht Perl genau das, was die Dokumentation sagt:
Dazu wird die Eingabedatei umbenannt, die Ausgabedatei nach dem ursprünglichen Namen geöffnet und diese Ausgabedatei als Standard für print () -Anweisungen ausgewählt. Die Erweiterung, falls angegeben, wird verwendet, um den Namen der alten Datei zu ändern und eine Sicherungskopie zu erstellen [...]
Was dazu führt, dass ein neuer Symlink "somefile.bak" auf die unveränderte reale Datei verweist und eine neue, geänderte reguläre Datei "somefile" mit den Änderungen.
In vielen Fällen ist das Verfolgen des Symlinks das gewünschte Verhalten (auch wenn der korrekte Speicherort der .bak-Datei nicht eindeutig ist). Gibt es eine einfache Möglichkeit, dies zu tun, als in einem Wrapper nach Symlinks zu suchen und den Fall angemessen zu behandeln?
( sed
Tut das Gleiche, für das, was es wert ist.)
-p -i
Ihr Skript erneut zu implementieren .Antworten:
Ich frage mich, ob das kleine
sponge
Allzweck-Dienstprogramm ("Standardeingabe aufsaugen und in eine Datei schreiben") von moreutils in diesem Fall hilfreich ist und ob es dem Symlink folgt.Der Autor beschreibt das
sponge
so:quelle
sponge
eine solche Anwendung in der Praxis getestet ? Was mich betrifft: noch nicht. Könnten Sie bitte einen Kommentar hinterlassen, der besagt, ob es sich bei einem Test so verhalten hat, wie es hier gewünscht wird? Oh, ich sehe den Kommentar. Danke für die Bestätigung!file
in Ihrem obigen Beispiel um einen Symlink handelt, wird der Link alleine gelassen und die reale Datei geändert.Wenn Sie wissen, dass
somefile
es sich um einen Symlink handelt, können Sie den vollständigen Pfad zur Datei wie folgt angeben:perl -pi.bak -e 's/foo/bar/' $(readlink somefile)
Auf diese Weise bleibt der ursprüngliche Symlink erhalten, da die Ersetzung jetzt direkt mit der ursprünglichen Datei erfolgt.
quelle
readlink
kann immer noch ein anderer Symlink sein. Am besten wäre es zu verwenden ,-f
oder-e
sofern verfügbar , oderzsh
‚s$file:P
oder(:P)
glob Qualifier wie @ikegami gezeigt einen Symlink-freien Weg zu bekommen.Wenn es sich um eine einzelne Datei handelt, sieht der Befehl folgendermaßen aus:
Die Lösung lautet dann:
Dies behandelt sowohl Symlinks als auch Nicht-Symlinks.
Wenn Sie mit einer beliebig großen Anzahl von Dateien arbeiten, sieht der Befehl folgendermaßen aus:
Die Lösung lautet dann:
Dies behandelt sowohl Symlinks als auch Nicht-Symlinks.
Warnung
readlink
ist kein Standardbefehl, daher variieren das Vorhandensein, die Argumente und die Funktionalität des Befehls je nach System. Überprüfen Sie daher unbedingt Ihre Dokumentation. Zum Beispiel haben einige Implementierungen-f
(die Sie auch hier verwenden könnten), aber nicht-e
, einige auch nicht.busybox
‚sreadlink -f
verhält sich wie GNUreadlink -e
. Und einige Systeme haben einenrealpath
Befehl,readlink
der sich im Allgemeinen wie GNU verhältreadlink -f
.Beachten Sie, dass mit GNU
readlink -e
Symlinks, die nicht in eine vorhandene Datei aufgelöst werden können, stillschweigend entfernt werden.quelle
$var:P
funktioniert bei mir nicht. (X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'
Ausgängetmp:P
)$var:P
. Bei älteren Versionen können Sie immer$var:A
stattdessen verwenden. Siehe das Handbuch für die Unterschiede und zsh.org/mla/users/2016/msg00593.html als Begründung für die Einführung:P
(die echterealpath()
Schnittstelle).:A
Wurde in 4.3.10 (2009) hinzugefügt, GNUreadlink -z
in 2012, mir ist keine anderereadlink
Implementierung bekannt, die dies unterstützt.-z
) Beachten Sie, dass Sie bei GNUxargs
im Allgemeinen die-r
Option wünschen, es sei denn, Sie können garantieren, dass die Eingabe nicht leer ist. Hier ist es keine große Sache (es sei denn, derperl
Code enthält eineBEGIN
/END
-Anweisung), Sie würden nur eine-i used with no filenames on the command line, reading from STDIN.
Warnung erhalten, wenn dies passiert.-r
die Dokumentation falsch gelesen . Ich dachte, ich hätte das Gegenteil von dem getan, was es tut. Readded.