sed “e” und “g” Flags funktionieren nicht zusammen

7

Angesichts dessen:

echo AAA | sed -r 's/A/echo B/ge'

Ich verstehe das:

Becho Becho B

Ich hätte gedacht, ich würde "BBB" bekommen. Dies ist mit GNU sed Version 4.2.1. Was ist los und wie kann ich das Ausführungsflag verwenden und mehrere Ersetzungen in einer Zeile vornehmen (von der Shell, nicht von Perl et al.)?

Spinkus
quelle

Antworten:

8

Die Flags arbeiten entgegengesetzt zu dem, was Sie erwarten. Die Dokumentation von /eist für die Aufzeichnung:

Mit diesem Befehl kann eine Eingabe von einem Shell-Befehl in den Musterraum geleitet werden. Wenn eine Ersetzung vorgenommen wurde, wird der im Musterraum gefundene Befehl ausgeführt und der Musterraum durch seine Ausgabe ersetzt. Ein nachfolgender Zeilenumbruch wird unterdrückt. Ergebnisse sind undefiniert, wenn der auszuführende Befehl ein Nullzeichen enthält. Dies ist eine GNU sed Erweiterung.

Das ist ein bisschen gewunden geschrieben. s///Dies bedeutet, dass nach Abschluss eines Befehls für diese Zeile bei einer Änderung die (neue) Zeile als Befehl ausgeführt und ihre Ausgabe als Ersatz für diese Zeile verwendet wird.

Also für Ihren gegebenen Befehl:

echo AAA | sed -r 's/A/echo B/ge'

es ersetzt zuerst jedes Adurch echo Bund führt dann das Ergebnis als Befehl aus. Es hat (grob gesagt) den gleichen Effekt wie:

echo AAA | sed -r 's/A/echo B/g' | sh

GNU sedunterstützt den gewünschten Modus nicht direkt, obwohl Sie ihn bei Bedarf mit einem komplexeren Skript vortäuschen können. Alternativ hat Perls /eModifikator für seinen sBefehl das gewünschte Verhalten, jedoch stattdessen mit Perl-Ausdrücken.

Michael Homer
quelle
Aha - Ausführen des Befehls, den es im Musterraum findet, nachdem die gesamte Zeile verarbeitet wurde! OK, das macht irgendwie Sinn. Obwohl Perl mit diesen beiden gesetzten Flags macht, was ich wollte. Danke.
Spinkus
4

Sie sind immer mehrere Ersatz, aber bekommt man nicht mehrere Ausführungen. Das Muster wird ausgeführt, sobald alle Ersetzungen vorgenommen wurden.

Ohne die eFlagge das Ergebnis von

echo AAA | sed -r 's/A/echo B/g'

ist

echo Becho Becho B

Also das ist die Befehlszeile , die , wenn Sie ausgeführt hat sie die umfassen eFlagge, die äquivalent ist

echo 'Becho Becho B'
PM 2Ring
quelle
2

Um 'BBB' von 'AAA' mit dem Befehl 's' von GNU sed mit dem Flag 'e' zu erhalten, kann man Folgendes tun:

echo AAA | sed -re 's/A/echo -n B;/ge'

Das 'AAA' wird durch 'echo -n B; echo -n B; echo -n B; ', was, wenn es schließlich ausgeführt wird, zu 3 nacheinander ausgeführten Echo-Befehlen führt, einen für jede der globalen Übereinstimmungen. Das '-n' lässt die Zeilenvorschubzeichen in der Echoausgabe weg, sodass die 'B' in einer Zeile landen (sed fügt jedoch einen Zeilenvorschub für sich an, wenn der Musterbereich endgültig gedruckt wird).

Serolmie
quelle
1

Ein paar Dinge:

(1) Der genaue Anwendungsfall, den Sie beschreiben, kann mit nur behandelt werden

echo AAA | sed 's/A/B/g'

(2) Wenn dies für die Ausführung genau das ist, was Sie möchten (für eine fortgeschrittenere Verwendung als nur das Echo), können Sie das eFlag als letzten Schritt verwenden:

echo AAA | sed -r 's/A/B/g;s/(.*)/echo \1/e'

(3) Wenn Sie den Befehl nur ausführen möchten, wenn der ERSTE Ersatzbefehl etwas ersetzt hat, verwenden Sie einen Zweig:

echo AAA | sed -r 's/A/B/g;te;b;:e;s/(.*)/echo \1/e'

Diese funktionieren nur in GNU sedwie oben beschrieben. BSD sed(zumindest die Version, die ich habe) unterstützt die -rOption nicht und erfordert ein Ende der Zeichenfolge, um einem Zweignamen zu folgen. (Sie können diesen letzten Punkt umgehen, indem Sie mehrere -eOptionen mit Argumenten hinzufügen .)

Beachten Sie, dass mit dem angegebenen Eingang (AAA) diese drei Einzeiler alle funktional identisch sind. Aber wenn der echoBefehl in etwas anderes geändert oder die -nOption an übergeben sedwürde, würden Sie den Unterschied sehen.

Platzhalter
quelle