it-swarm.com.de

bearbeiten Sie die Datei an Ort und Stelle

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?

216
amphibient

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.

320
choroba

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.

68
Steve

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

44
diadyne

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
21
minhas23

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
11
Dwight Spencer

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.

10
William Pursell

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.txtmit 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.

7
Sergio A.

Sie könnten vi verwenden

vi -c '%s/foo/bar/g' my.txt -c 'wq'
7
mench

Wenn Sie die gleiche Anzahl Zeichen ersetzen und „In-Place“ -Bearbeitung der Dateien sorgfältig gelesen haben ...

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.

3
fedorqui
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.

3
JJM

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.

1
Thor

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 /' {} \;
1
Robert

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.

0
jlettvin