Frage

In meinem Bash-Skript Ich habe ein externes (erhalten von Benutzer) Zeichenfolge, die ich in sed Mustern verwendet werden soll.

REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"

Wie kann ich die $REPLACE String entweichen, so wäre es sicher von sed als wörtliche Ersatz akzeptiert werden?

Hinweis: Die KEYWORD ist eine dumme Teilkette ohne Streichhölzer usw. Es wird nicht vom Benutzer bereitgestellt

.
War es hilfreich?

Lösung

Warnung : Das tut nicht betrachtet Zeilenumbrüche. Für eine Antwort in der Tiefe finden Sie unter diese SO-Frage anstatt zu entkommen. (Danke, Ed Morton & Niklas Peter)

Beachten Sie, dass alles zu entkommen ist eine schlechte Idee. Sed braucht viele Zeichen zu entkommen zu get ihre besondere Bedeutung. Zum Beispiel, wenn Sie eine Ziffer in dem Ersatz-String entkommen, wird es zu einem Rückreferenzierung dreht in.

Wie Ben Blank sagte, gibt es nur drei Zeichen, die in der Ersatzzeichenfolge (entkommt selbst, Schrägstrich für Ende der Anweisung und & für ersetzen alle) entgangen sein müssen:

sed -e 's/[\/&]/\\&/g'

Wenn Sie jemals die KEYWORD Zeichenfolge entkommen müssen, die folgende ist, die Sie brauchen:

sed -e 's/[]\/$*.^[]/\\&/g'

Denken Sie daran, wenn Sie ein anderes Zeichen als / als Trennzeichen verwenden, müssen Sie den Schrägstrich in den Ausdrücken ersetzen oben wih das Zeichen, das Sie verwenden. Siehe PeterJCLaw Kommentar zur Erläuterung.

Editiert: Aufgrund einiger Sonderfälle bisher nicht berücksichtigt, haben die obigen Befehle mehrmals geändert. Überprüfen Sie die Versionsgeschichte für Details.

Andere Tipps

Der sed-Befehl können Sie andere Zeichen verwenden, anstatt / als Trennzeichen:

sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'

Die doppelten Anführungszeichen sind kein Problem.

Die einzigen drei wörtlichen Zeichen, die speziell in der Klausel ersetzen behandelt werden, sind / (um die Klausel in der Nähe), \ (Zeichen, Rückreferenzierung, usw zu entkommen.) Und & (um das Spiel in den Ersatz enthalten). Daher alles, was Sie tun müssen, ist diese drei Escape-Zeichen:

sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"

Beispiel:

$ export REPLACE="'\"|\\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
foo'"|\/><&!bar

Basierend auf Pianosaurus regulären Ausdrücke, ich habe eine Bash-Funktion, die sowohl Schlüsselwort und Ersatz entkommt.

function sedeasy {
  sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
}

Hier ist, wie Sie es verwenden:

sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf

Es ist ein bisschen spät zu reagieren ... aber es gibt eine viel einfachere Art und Weise, dies zu tun. ändern, nur das Trennzeichen (das heißt, das Zeichen, das Feld trennt). Anstatt also s/foo/bar/ schreiben Sie s|bar|foo.

Und hier ist die einfache Möglichkeit, dies zu tun:

sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g'

Die resultierende Ausgabe ist frei von dieser fiesen DEFINER-Klausel.

Es stellt sich heraus Sie die falsche Frage sind zu fragen. Ich fragte auch die falsche Frage. Der Grund, warum es falsch ist, ist der Anfang des ersten Satzes. "In meinem bash Skript ..."

Ich hatte die gleiche Frage und machte die gleichen Fehler. Wenn Sie bash verwenden, müssen Sie nicht sed verwenden String Ersatz zu tun (und es ist viel Reiniger, um die Funktion in bash gebaut ersetzen verwenden).

Statt etwas wie, zum Beispiel:

function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A="$(escape-all-funny-characters 'KEYWORD')"
B="$(escape-all-funny-characters '<funny characters here>')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"

Sie verwenden können bash verfügt ausschließlich:

INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"

Mit awk - es ist sauberer:

$ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare

Hier ist ein Beispiel eines AWK ich vor einiger Zeit verwendet. Es ist ein AWK, die neue AWKS druckt. AWK und SED ähnlich ist es vielleicht eine gute Vorlage sein.

ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds

Es sieht übertrieben, aber irgendwie, dass Kombination von Zitaten arbeitet die "gedruckt als Literale zu halten. Dann, wenn ich mich richtig erinnere die vaiables sind nur mit Zitaten wie folgt umgeben: „$ 1“. Versuchen Sie es, lassen Sie mich wissen, wie es funktioniert mit SED.

Ich habe eine Verbesserung gegenüber der sedeasy-Funktion, die mit Sonderzeichen wie Tab brechen.

function sedeasy_improved {
    sed -i "s/$(
        echo "$1" | sed -e 's/\([[\/.*]\|\]\)/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/$(
        echo "$2" | sed -e 's/[\/&]/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/g" "$3"
}

Also, was ist anders? $1 und $2 in Anführungszeichen Shell-Erweiterungen zu vermeiden und Tabs oder doppelte Leerzeichen zu erhalten.

Zusätzliche Leitungen | sed -e 's:\t:\\t:g' (Ich mag : als Token), die eine Registerkarte in \t verwandelt.

Sie alle das Vergnügen nicht vergessen, dass mit der Schale Einschränkung auftritt um "und‚

so (in KSH)

Var=">New version of \"content' here <"
printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar

echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"

Wenn der Fall sein passiert, dass Sie ein zufälliges Passwort generieren Muster passieren sed ersetzen, dann wählen Sie vorsichtig sein, über die in der zufälligen Zeichenfolge gesetzt. Wenn Sie ein Passwort durch Codierung Wert als base64 gemacht wählen, dann gibt es nur Zeichen, die sowohl möglich in Base64 und ist auch ein Sonderzeichen in sed Muster ersetzen. Das Zeichen „/“, und ist leicht von dem Passwort entfernen Sie generieren:

# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;

Wenn Sie gerade suchen Variablenwert in sed Befehl ersetzen dann einfach entfernen Beispiel:

sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test

Ein einfacher Weg, dies zu tun, einfach baut die Zeichenfolge vor der Hand und es als Parameter für sed mit

rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring  test.txt
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top