it-swarm.com.de

Suchen und Ersetzen in Datei und Datei überschreiben funktioniert nicht, die Datei wird geleert

Ich möchte eine HTML-Datei über die Befehlszeile suchen und ersetzen.

Mein Befehl sieht ungefähr so ​​aus:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

Wenn ich dies ausführe und danach die Datei anschaue, ist sie leer. Es löschte den Inhalt meiner Datei.

Wenn ich dies nach dem erneuten Wiederherstellen der Datei ausführe:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

stdout ist der Inhalt der Datei, und das Suchen und Ersetzen wurde ausgeführt.

Warum passiert dies?

574
BBales

Wenn die Shell> index.html in der Befehlszeile sieht, öffnet sie die Datei index.html für Schreiben und löscht den gesamten vorherigen Inhalt.

Um dies zu beheben, müssen Sie die Option -i an sed übergeben, um die Änderungen inline vorzunehmen und eine Sicherungskopie der Originaldatei zu erstellen, bevor die Änderungen an Ort und Stelle vorgenommen werden:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Ohne die .bak-Datei schlägt der Befehl auf einigen Plattformen wie Mac OSX fehl.

886
codaddict

Ein alternatives, nützliches Muster ist:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

Dies hat fast den gleichen Effekt, ohne die Option -i zu verwenden. Außerdem bedeutet dies, dass die Eingabedatei nicht blockiert wird, wenn das sed-Skript aus irgendeinem Grund fehlschlägt. Wenn die Bearbeitung erfolgreich ist, bleibt keine Sicherungsdatei übrig. Diese Art von Redewendung kann in Makefiles nützlich sein.

Sehr viele Seds haben die Option -i, aber nicht alle. Die Posix Sed ist eine, die es nicht tut. Wenn Sie also Portabilität anstreben, sollten Sie dies vermeiden.

201
Norman Gray
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

Dies führt eine globale direkte Ersetzung in der Datei index.html durch. Das Zitieren der Zeichenfolge verhindert Probleme mit Leerzeichen bei der Abfrage und beim Ersetzen.

88
Rich Apodaca

verwenden Sie die Option -i von sed, z.

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html
56
Kevin

So ändern Sie mehrere Dateien (und speichern jeweils eine Sicherungskopie als * .bak):

Perl -p -i -e "s/\|/x/g" *  

nimmt alle Dateien in ein Verzeichnis und ersetzt | durch x Dies wird als "Perl-Torte" bezeichnet (einfach wie eine Torte).

18
Stenemo

Sie sollten versuchen, die Option -i für die direkte Bearbeitung zu verwenden.

14
uloBasEI

Warnung: Dies ist eine gefährliche Methode! Sie missbraucht die I/O-Puffer unter Linux und kann mit bestimmten Pufferoptionen kleine Dateien bearbeiten. Es ist eine interessante Neugier. Aber verwende es nicht für eine reale Situation!

Neben der Option -i von sed können Sie das Hilfsprogramm tee verwenden.

Von man:

tee - von der Standardeingabe lesen und in die Standardausgabe und Dateien schreiben

Die Lösung wäre also:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

- hier wird der tee wiederholt, um sicherzustellen, dass die Pipeline gepuffert ist. Dann werden alle Befehle in der Pipeline blockiert, bis sie Eingaben zum Bearbeiten erhalten. Jeder Befehl in der Pipeline startet, wenn die Upstream-Befehle 1 Byte-Puffer (die Größe ist definiert irgendwo ) an die Eingabe des Befehls geschrieben haben. Der letzte Befehl tee index.html, mit dem die Datei zum Schreiben geöffnet und daher geleert wird, wird ausgeführt, nachdem die Upstream-Pipeline beendet wurde und die Ausgabe sich im Puffer innerhalb der Pipeline befindet.

Höchstwahrscheinlich funktioniert Folgendes nicht:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

- Es werden beide Befehle der Pipeline gleichzeitig ohne Blockierung ausgeführt. (Ohne Blockierung sollte die Pipeline die Bytes Zeile für Zeile anstelle von Puffer für Puffer durchlassen. Wie beim Ausführen von cat | sed s/bar/GGG/. Ohne Blockierung ist sie interaktiver und normalerweise werden Pipelines mit nur 2 Befehlen ohne Pufferung und Blockierung ausgeführt. Längere Pipelines sind gepuffert.) Der tee index.html öffnet die Datei zum Schreiben und wird geleert. Wenn Sie die Pufferung jedoch immer aktivieren, funktioniert auch die zweite Version.

6
xealits
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

Wenn Sie einen Link haben, den Sie hinzufügen möchten, versuchen Sie dies. Suchen Sie wie oben nach der URL (beginnend mit https und endend mit.com hier) und ersetzen Sie sie durch eine URL-Zeichenfolge. Ich habe hier eine Variable $pub_url verwendet. s bedeutet hier Suche und g bedeutet globales Ersetzen.

Es klappt !

6
Kaey

Das Problem mit dem Befehl

sed 'code' file > file

ist, dass file von der Shell abgeschnitten wird, bevor sed es tatsächlich verarbeiten kann. Als Ergebnis erhalten Sie eine leere Datei.

Der beste Weg, dies zu tun, besteht darin, -i zu verwenden, um es an Ort und Stelle zu bearbeiten, wie andere Antworten vorgeschlagen haben. Dies ist jedoch nicht immer das, was Sie wollen. -i erstellt eine temporäre Datei, die dann zum Ersetzen der Originaldatei verwendet wird. Dies ist problematisch, wenn Ihre ursprüngliche Datei ein Link war (der Link wird durch eine reguläre Datei ersetzt). Wenn Sie Verknüpfungen beibehalten müssen, können Sie die Ausgabe von sed mit einer temporären Variablen speichern, bevor Sie sie in die Datei zurückschreiben:

tmp=$(sed 'code' file); echo -n "$tmp" > file

Verwenden Sie noch besser printf anstelle von echo, da echo wahrscheinlich \\ als \ in einigen Shells verarbeitet (z. B. Bindestrich):

tmp=$(sed 'code' file); printf "%s" "$tmp" > file
4

Und die ed Antwort:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

Um zu wiederholen, was Codeaddict beantwortet ist, verarbeitet die Shell zuerst die Umleitung und löscht die Datei "input.html" und dann ruft die Shell den Befehl "sed" auf und übergibt ihm eine jetzt leere Datei.

3
glenn jackman

Sie können Vim im Ex-Modus verwenden:

ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html
  1. % Alle Zeilen auswählen

  2. x speichern und schließen

2
Steven Penny

Ich habe nach der Option gesucht, in der ich den Linienbereich definieren und die Antwort finden kann. Zum Beispiel möchte ich Host1 in Host2 von Zeile 36-57 ändern.

sed '36,57 s/Host1/Host2/g' myfile.txt > myfile1.txt

Sie können auch die Option gi verwenden, um die Groß- und Kleinschreibung zu ignorieren.

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt
0
user8117884

Bei allem Respekt vor den obigen korrekten Antworten ist es immer eine gute Idee, solche Skripte "trocken laufen zu lassen", damit Sie Ihre Datei nicht beschädigen und von vorne beginnen müssen.

Lassen Sie Ihr Skript einfach die Ausgabe in die Befehlszeile schreiben, anstatt sie in die Datei zu schreiben, zum Beispiel so:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

OR

less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g 

Auf diese Weise können Sie die Ausgabe des Befehls anzeigen und überprüfen, ohne dass Ihre Datei abgeschnitten wird.

0
Nestor Milyaev