Ich versuche herauszufinden, ob es möglich ist, eine Datei in einem einzelnen sed-Befehl zu bearbeiten, ohne dassmanuellden bearbeiteten Inhalt in eine neue Datei streamen und dann die neue Datei in den ursprünglichen Dateinamen umbenennen muss. Ich habe die -i
-Option ausprobiert, aber mein Solaris-System sagte, dass -i
eine illegale Option ist. Gibt es einen anderen Weg?
Mit der Option -i
wird der bearbeitete Inhalt in eine neue Datei gestreamt und anschließend im Hintergrund umbenannt.
Beispiel:
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
und
sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
auf macOS.
Auf einem System, in dem sed
nicht die Möglichkeit hat, Dateien zu bearbeiten, denke ich, wäre die bessere Lösung die Verwendung von Perl
:
Perl -pi -e 's/foo/bar/g' file.txt
Obwohl dadurch eine temporäre Datei erstellt wird, wird das Original ersetzt, da ein leeres Suffix/eine leere Erweiterung angegeben wurde.
Beachten Sie, dass unter OS X beim Ausführen dieses Befehls möglicherweise seltsame Fehler wie "ungültiger Befehlscode" oder andere seltsame Fehler auftreten. Um dieses Problem zu beheben, versuchen Sie es
sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
Dies liegt daran, dass die -i
-Option in der OSX-Version von sed
ein extension
-Argument erwartet, sodass Ihr Befehl tatsächlich als extension
-Argument analysiert und der Dateipfad als Befehlscode interpretiert wird. Quelle: https://stackoverflow.com/a/19457213
Folgendes funktioniert gut auf meinem Mac
sed -i.bak 's/foo/bar/g' sample
Wir ersetzen foo durch einen Balken in der Beispieldatei. Die Sicherung der Originaldatei wird in sample.bak gespeichert
Verwenden Sie für die Inline-Bearbeitung ohne Sicherung den folgenden Befehl
sed -i'' 's/foo/bar/g' sample
Zu beachten ist, dass sed
keine eigenen Dateien schreiben kann. Der einzige Zweck von sed ist es, als Editor für den "Stream" zu fungieren (dh Pipelines von stdin, stdout, stderr und anderen >&n
-Puffern, Sockets und dergleichen). Zu diesem Zweck können Sie einen anderen Befehl tee
verwenden, um die Ausgabe in die Datei zurückzuschreiben. Eine weitere Option besteht darin, einen Patch zu erstellen, indem der Inhalt in diff
geleitet wird.
Abschlagmethode
sed '/regex/' <file> | tee <file>
Patch-Methode
sed '/regex/' <file> | diff -p <file> /dev/stdin | patch
AKTUALISIEREN:
Beachten Sie auch, dass der Patch die Datei von Zeile 1 der diff-Ausgabe ändert:
Patch muss nicht wissen, auf welche Datei zugegriffen werden soll, da sich dies in der ersten Zeile der Ausgabe von diff befindet:
$ echo foobar | tee fubar
$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar 2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin 2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar
$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar
Mit sed
können Sie nicht das tun, was Sie möchten. Selbst Versionen von sed
, die die -i
-Option zum Bearbeiten einer Datei an Ort und Stelle unterstützen, tun genau das, was Sie explizit angegeben haben, als wollten Sie nicht: Sie schreiben in eine temporäre Datei und benennen die Datei anschließend um. Aber vielleicht können Sie einfach ed
verwenden. Um beispielsweise alle Vorkommen von foo
in bar
in der Datei file.txt
zu ändern, können Sie Folgendes tun:
echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt
Die Syntax ähnelt sed
, ist aber sicherlich nicht genau dieselbe.
Aber vielleicht sollten Sie überlegen, warum Sie keine umbenannte temporäre Datei verwenden möchten. Selbst wenn Sie keine -i
-Unterstützung für sed
haben, können Sie leicht ein Skript schreiben, das die Arbeit für Sie erledigt. Anstelle von sed -i 's/foo/bar/g' file
können Sie inline file sed 's/foo/bar/g'
ausführen. Ein solches Skript ist einfach zu schreiben. Zum Beispiel:
#!/bin/sh -e
IN=$1
shift
trap 'rm -f $tmp' 0
tmp=$( mktemp )
<$IN "[email protected]" >$tmp && cat $tmp > $IN # preserve hard links
sollte für die meisten Anwendungen ausreichend sein.
sed unterstützt die direkte Bearbeitung. Von man sed
:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
Beispiel:
Angenommen, Sie haben eine Datei hello.txt
mit dem Text:
hello world!
Wenn Sie eine Sicherungskopie der alten Datei erstellen möchten, verwenden Sie Folgendes:
sed -i.bak 's/hello/bonjour' hello.txt
Sie erhalten am Ende zwei Dateien: hello.txt
mit dem Inhalt:
bonjour world!
und hello.txt.bak
mit dem alten Inhalt.
Wenn Sie keine Kopie behalten möchten, übergeben Sie den Erweiterungsparameter nicht.
Sie könnten vi verwenden
vi -c '%s/foo/bar/g' my.txt -c 'wq'
Sie können auch den Umleitungsoperator <>
verwenden, um die Datei zum Lesen und Schreiben zu öffnen:
sed 's/foo/bar/g' file 1<> file
Sehen Sie es live:
$ cat file
hello
i am here # see "here"
$ sed 's/here/away/' file 1<> file # Run the `sed` command
$ cat file
hello
i am away # this line is changed now
Aus Bash-Referenzhandbuch → 3.6.10 Dateideskriptoren zum Lesen und Schreiben öffnen :
Der Umleitungsoperator
[n]<>Word
bewirkt, dass die Datei, deren Name die Erweiterung von Word ist, für .__ geöffnet wird. Lesen und Schreiben des Dateideskriptors n oder des Dateideskriptors 0 wenn n nicht angegeben ist. Wenn die Datei nicht vorhanden ist, wird sie erstellt.
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
Sollte alle Hardlinks beibehalten, da die Ausgabe zurückgeschickt wird, um den Inhalt der Originaldatei zu überschreiben und keine spezielle Version von sed erforderlich ist.
Sie haben nicht angegeben, welche Shell Sie verwenden, aber mit zsh können Sie das =( )
-Konstrukt verwenden, um dies zu erreichen. Etwas im Sinne von:
cp =(sed ... file; sync) file
=( )
ähnelt >( )
, erstellt jedoch eine temporäre Datei, die automatisch gelöscht wird, wenn cp
beendet wird.
Sehr gute Beispiele. Ich hatte die Herausforderung, viele Dateien an Ort und Stelle zu bearbeiten, und die Option -i scheint die einzige vernünftige Lösung zu sein, die sie im Befehl find verwendet. Hier das Skript zum Hinzufügen von "version:" vor der ersten Zeile jeder Datei:
find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;
Wie Moneypenny in Skyfall sagte: "Manchmal sind alte Wege am besten." Kincade sagte später etwas Ähnliches.
$ printf ', s/false/true/g\nw\n' | ed {YourFileHere}
Viel Spaß beim Bearbeiten . "\ Nw\n" hinzugefügt, um die Datei zu schreiben. Entschuldigung für die verspätete Beantwortung der Anfrage.