Wie ersetze ich Strings mit Schrägstrichen durch sed?

147

Ich habe ein Visual Studio-Projekt, das lokal entwickelt wird. Codedateien müssen auf einem Remote-Server bereitgestellt werden. Das einzige Problem ist, dass URLs enthalten sind, die fest codiert sind.

Das Projekt enthält URLs wie ? Page = one . Damit der Link auf dem Server gültig ist, muss er / page / one sein .

Ich habe beschlossen, alle URLs in meinen Codedateien vor der Bereitstellung durch sed zu ersetzen, bin aber bei Schrägstrichen geblieben.

Ich weiß, dass dies keine schöne Lösung ist, aber es ist einfach, würde mir viel Zeit sparen. Die Gesamtzahl der zu ersetzenden Zeichenfolgen beträgt weniger als 10. Die Gesamtzahl der zu überprüfenden Dateien beträgt ~ 30.

Ein Beispiel, das meine Situation beschreibt, ist unten:

Befehl, den ich benutze:

sed -f replace.txt < a.txt > b.txt

replace.txt, das alle Zeichenfolgen enthält:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Inhalt von b.txt, nachdem ich meinen sed-Befehl ausgeführt habe:

pageone
pagetwo
pagethree

Was ich möchte, dass b.txt enthält:

/page/one
/page/two
/page/three
afaf12
quelle
1
Mögliches Duplikat der Suche und Ersetzung von Zeichenfolgen mit /
Damien MATHIEU
3
Mögliches Duplikat von Schrägstrichen in sed ersetzen
Tripleee

Antworten:

274

Der einfachste Weg wäre, ein anderes Trennzeichen in Ihren Such- / Ersetzungszeilen zu verwenden, z.

s:?page=one&:pageone:g

Sie können jedes Zeichen als Trennzeichen verwenden, das nicht Teil einer der beiden Zeichenfolgen ist. Oder Sie könnten es mit einem Backslash entkommen:

s/\//foo/

Welche ersetzen würde /mit foo. Sie möchten den maskierten Backslash in Fällen verwenden, in denen Sie nicht wissen, welche Zeichen in den Ersatzzeichenfolgen vorkommen können (z. B. wenn es sich um Shell-Variablen handelt).

Lurker
quelle
1
> Oder Sie könnten mit einem Backslash davonkommen. Ein Beispiel dafür wäre nützlicher, da Sie nicht immer wissen, welche Zeichen in einer Zeichenfolge enthalten sind, um etwas anderes auswählen zu können. zB dies: echo / | sed s / \ // a / g funktioniert nicht: sed: -e Ausdruck # 1, char 5: unbekannte Option für `s '
Max Waterman
1
Könnten Sie dann eine hinzufügen? Danke :) Ich fand Umgebung in doppelten Anführungszeichen scheint zu funktionieren: echo / | sed "s / \ // a / g"
Max Waterman
@MaxWaterman Es ist die Standardarbeitsanweisung, wenn sedder Befehl regex in doppelte Anführungszeichen gesetzt wird. Ich habe sie in meiner Antwort nicht verwendet, weil ich nicht die gesamte sedBefehlszeile sedangezeigt habe, sondern nur die Regex-Befehlszeichenfolge, wie es das OP getan hatte. Wenn Sie es wie das OP in eine Datei einfügen, benötigen Sie die Anführungszeichen nicht.
Lurker
Ja, fair genug (obwohl es vielleicht erwähnt werden könnte). Dieses Beispiel hilft. Ich habe festgestellt, dass ich manchmal sehr viele Backslashes einfügen muss ... und es wird wirklich verwirrend. zB -e "s / '/ \\\\\\\ & / g" Ich denke, der Text ist jedoch falsch: "Was würde \ durch foo ersetzen" - sollte "Was würde / durch foo ersetzen" sein, nein?
Max Waterman
@ MaxWaterman, danke, dass du das auf \ vs. / verstanden hast. Behoben. Wenn Sie einen sedBefehl in einem Shell-Skript haben, sind möglicherweise weitere Backslashes erforderlich (jeder Backslash muss erneut mit einem Backslash versehen werden).
Lurker
105

Der sBefehl kann ein beliebiges Zeichen als Trennzeichen verwenden. Welches Zeichen auch immer kommt, nachdem das sverwendet wird. Ich wurde erzogen, um a zu benutzen #. Wie so:

s#?page=one&#/page/one#g
Tom Anderson
quelle
5
Die Manpage für das BSD sed unter OS X sagt über den Befehl s : Ersetzen Sie die erste Instanz des regulären Ausdrucks im Musterraum durch die Ersetzungszeichenfolge. Jedes andere Zeichen als Backslash oder Newline kann anstelle eines Schrägstrichs verwendet werden, um die RE und die Ersetzung abzugrenzen. Ich würde Geld wetten, dass die Manpage für GNU sed etwas Ähnliches sagt.
Tom Anderson
Die aktuell akzeptierte Antwort ist im Grunde die gleiche wie diese und wurde eine Minute zuvor veröffentlicht!
Tom Anderson
61

Eine sehr nützliche, aber weniger bekannte Tatsache über sed ist, dass der vertraute s/foo/bar/Befehl jede Interpunktion verwenden kann, nicht nur Schrägstriche. Eine übliche Alternative ist s@foo@bar@, aus der hervorgeht, wie Sie Ihr Problem lösen können.

John Zwinck
quelle
Genialer Rat, wenn Sie Schrägstriche ersetzen möchten. Vielen Dank!
mbb
9

füge \ vor Sonderzeichen hinzu:

s/\?page=one&/page\/one\//g

etc.

Ilja
quelle
4
Ich habe vielleicht etwas verpasst, aber ich habe es versucht und es scheint nicht zu funktionieren. Es schien naheliegend, es zu versuchen, aber wenn ich recht habe und es tatsächlich nicht funktioniert, warum sollte ich es posten?
Codenoob
4
@codenoob (und jeder andere, der hierher kommt) - das 's' am Anfang ist erforderlich. s/foo\/bar/foo_bar/wird funktionieren, wird aber /foo\/bar/foo_bar/nicht.
MynockSpit
5

In einem System, das ich entwickle, ist die durch sed zu ersetzende Zeichenfolge Eingabetext eines Benutzers, der in einer Variablen gespeichert und an sed übergeben wird.

Wie bereits in diesem Beitrag erwähnt, wird sed bei einem Syntaxfehler beendet, wenn die im sed-Befehlsblock enthaltene Zeichenfolge das von sed verwendete Trennzeichen enthält. Betrachten Sie das folgende Beispiel:

Das funktioniert:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Dies bricht:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Das Ersetzen des Standardtrennzeichens ist in meinem Fall keine robuste Lösung, da ich den Benutzer nicht daran hindern wollte, bestimmte Zeichen einzugeben, die von sed als Trennzeichen verwendet werden (z. B. "/").

Das Problem kann jedoch behoben werden, wenn das Trennzeichen in der Eingabezeichenfolge nicht angezeigt wird. Betrachten Sie die folgende Lösung, bei der das Trennzeichen in der Eingabezeichenfolge systematisch maskiert wird, bevor es von sed analysiert wird. Ein solches Escapezeichen kann als Ersatz mit sed selbst implementiert werden. Dieser Ersatz ist auch dann sicher, wenn die Eingabezeichenfolge das Trennzeichen enthält. Dies liegt daran, dass die Eingabezeichenfolge nicht Teil des Befehlsblocks sed ist:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

Ich habe dies in eine Funktion konvertiert, die von verschiedenen Skripten verwendet wird:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}
Yoav Drori
quelle
1
Ihre Antwort für mich war, dass wenn der WERT, den Sie verwenden, um DEF_VALUE zu ersetzen, Schrägstriche enthält, Sie diese mit 3 Schrägstrichen VALUE="01\\\/01\\\/2018"
umgehen müssen, damit
3

Diese Zeile sollte für Ihre 3 Beispiele funktionieren:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • Früher habe ich -reinige Fluchtversuche gerettet.
  • Die Zeile sollte für Ihren Fall eins, zwei, drei generisch sein. Sie müssen das Sub nicht dreimal machen

Test mit deinem Beispiel (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
Kent
quelle
1

replace.txt sollte sein

s/?page=/\/page\//g
s/&//g
Ion Cojocaru
quelle
1

Tolle Antwort von Anonymous. \ löste mein Problem, als ich versuchte, Anführungszeichen in HTML-Zeichenfolgen zu umgehen.

Wenn Sie also sed verwenden, um einige HTML-Vorlagen (auf einem Server) zurückzugeben, verwenden Sie einen doppelten Backslash anstelle eines einfachen:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";
Sirar Salih
quelle
1

sedist die s tream ed itor , in denen Sie verwenden können |(Rohr) zu senden Standard - Streams (STDIN und STDOUT spezifisch) durch sedund verändern sie programmatisch im laufenden Betrieb , es ist ein handliches Werkzeug in der Philosophie Tradition Unix zu machen; Sie können Dateien jedoch auch direkt mit dem -iunten angegebenen Parameter bearbeiten .
Beachten Sie Folgendes :

sed -i -e 's/few/asd/g' hello.txt

s/zu verwendet s ubstitute den gefundenen Ausdruck fewmit asd:

Die wenigen, die Mutigen.


Der Asd, der Tapfere.

/gsteht für "global" und bedeutet dies für die gesamte Linie. Wenn Sie das weglassen /g(mit s/few/asd/, es müssen immer drei Schrägstriche vorhanden sein, egal was passiert) und fewzweimal in derselben Zeile erscheinen, wird nur der erste fewgeändert in asd:

Die wenigen Männer, die wenigen Frauen, die Mutigen.


Die asd Männer, die wenigen Frauen, die Mutigen.

Dies ist unter bestimmten Umständen hilfreich, z. B. beim Ändern von Sonderzeichen am Anfang von Zeilen (z. B. Ersetzen der Symbole, die größer als sind, um das vorherige Material in E-Mail-Threads zu zitieren, durch eine horizontale Registerkarte, während später in der Zeile eine zitierte algebraische Ungleichung verbleibt unberührt), aber in Ihrem Beispiel, in dem Sie angeben, dass es irgendwo few auftreten soll, sollten Sie es ersetzen /g.

Die folgenden zwei Optionen (Flags) werden zu einer zusammengefasst -ie:

-iOption zu bearbeiten verwendet i n Platz auf der Datei hello.txt.

-eOption gibt die e xpression / Befehl ausgeführt werden soll, in diesem Fall s/.

Hinweis: Es ist wichtig, dass Sie verwenden -i -e zum Suchen / Ersetzen verwenden. Wenn Sie dies tun -ie, erstellen Sie eine Sicherungskopie jeder Datei mit dem angehängten Buchstaben 'e'.

Chaminda Bandara
quelle
0

Eine einfachere Alternative ist die Verwendung von AWK wie bei dieser Antwort :

awk '$0="prefix"$0' file > new_file

Kennzeichen
quelle