Wie kann man zwei Muster mit `sed` austauschen?

462
monster

Ich verwende sedBefehl zu ändern, <active>trueum <active>falsein einer XML - Datei. Jetzt wenn ich benutze

sed 's/<active>true/<active>false/g' file.xml > file.xml 

Der Inhalt meiner Datei wird vollständig gelöscht. Bei Verwendung >>anstelle von >wird die Ausgabe am Ende angehängt, wie es erwartet wird.

  1. Wie kann ich erreichen, was ich machen möchte?
  2. Warum ist das >Verhalten so komisch?
  3. Was ich eigentlich tun möchte, ist zu ändern <active>true, <active>falsewenn <active>truevorhanden, und umgekehrt, wenn <active>falsein der Datei vorhanden ist. Gibt es einen Befehl, der das kann, oder muss ich ein Skript mit if-elsemeinem ursprünglichen Plan schreiben ?
0
2: [Diese Antwort] (https://unix.stackexchange.com/a/79039/108618). Untersuchen Sie "sed -i". Kamil Maciorowski vor 5 Jahren 1
@KamilMaciorowski kurz gesagt `file.xml` wurde abgeschnitten, bevor` sed` ausgeführt wurde. monster vor 5 Jahren 0
Ja. In Linux gibt es ein allgemeines Werkzeug, um dies zu vermeiden: [`sponge`] (https://linux.die.net/man/1/sponge). Kamil Maciorowski vor 5 Jahren 1
Danke, `sed -i` löste die Fragen 2 und 1, obwohl bei der Verwendung eines Schwammes der Befehl 'Befehl nicht gefunden' ausgegeben wurde monster vor 5 Jahren 0
In Debian oder Ubuntu ist "Schwamm" ein Teil des Pakets "moreutils", das standardmäßig nicht installiert ist. Ich denke, in anderen Bezirken ist die Situation ähnlich. Kamil Maciorowski vor 5 Jahren 0

1 Antwort auf die Frage

1
Kamil Maciorowski

Das Verhalten von >wird in dieser Antwort von Unix & Linux SE erläutert . Das Beispiel gibt es cat test.txt > test.txtund die Erklärung ist:

Das erste, was passiert, ist das Öffnen von bash test.txt, wodurch die Datei abgeschnitten wird. Es ist jetzt leer, bevor catmit test.txtals Argument ausgeführt wird.

Ihr sed '…' file.xml > file.xmllöst das gleiche Verhalten aus.

Ganz einfache Lösung mit einem einzigen sed:

sed -i 's/<active>true/<active>DUMMY/g s/<active>false/<active>true/g s/<active>DUMMY/<active>false/g' file.xml 

Die -iOption löst Ihr Problem mit der abgeschnittenen Datei. Der Befehl wechselt <active>truein <active>falseund umgekehrt. Beachten Sie, dass Sie nicht nur verwenden können

s/<active>true/<active>false/g;s/<active>false/<active>true/g 

weil der zweite Teil nicht erkennen kann, ob falsees sich um das Original falseoder um das Original handelt, das truegerade in umgewandelt wurde false. Dies führt dazu, dass jedes Matching trueoder falseEnding als true. Aus diesem Grund habe ich den temporären DUMMYErsatz verwendet. Vielleicht gibt es einen besseren Weg, ich weiß es noch nicht.

Die einzige Bedingung ist, dass die Zeichenfolge <active>DUMMYnicht in der Originaldatei angezeigt werden kann. Wenn es angezeigt wird, verwenden Sie einen anderen Dummy-String, der nicht sicher erscheint.