Warum gibt sed mir einen Fehler über ein nicht abgeschlossenes "s"?

9

Ich habe eine Reihe von Sed-Ersetzungen in einem Bash-Skript und erhalte eine Fehlermeldung bezüglich eines nicht abgeschlossenen `s'-Befehls. So sieht die sed-Linie aus:

sed -n -e "s/TMPFOO1/$FOO1/" -e "s/TMPFOO2/$FOO2/" -e "s/TMPFOO3/$FOO3/" -e "s/TMPFOO4/$FOO4/" -e "s/TMPFOO5/$FOO5/" /home/foo/template > /home/foo/template/finishedresult

Aus irgendeinem Grund mag Bash das nicht und ich bekomme eine Fehlermeldung

sed: -e expression #4, char 69: unterminated `s' command

Was fehlt mir hier? Wie kann ich die Variable von SED eingeben lassen? Es sieht für mich so aus, als wären sie alle beendet.

Mike B.
quelle
2
$ FOO4 enthält etwas Seltsames (z. B. "\" oder "\\"?), Das dazu führt, dass der Befehl sed s nicht beendet wird. (Deshalb denke ich, dass es ein abschließendes "\" ist, wodurch das nächste "/" als Zeichenteil der Ersetzungszeichenfolge behandelt wird, anstatt als Abschlusszeichen für den Befehl s)
Olivier Dulac

Antworten:

7

Sie können eine Variable in einem sed-Befehl nicht sicher interpolieren, da die Ersetzung durch die Shell und nicht durch sed erfolgt. Der Wert der Variablen wird zur sed-Syntax. Zum Beispiel in "s/TMPFOO1/$FOO1/", wenn $FOO1eine neue Zeile enthält, wird dies einen Syntaxfehler verursachen wie die, die Sie beobachtet. Wenn a $FOO1enthalten ist /, wird der sBefehl beendet und es kann ein Fehler oder die Ausführung anderer Befehle auftreten (wenn nach der /gültigen sed-Syntax eine gültige sed-Syntax vorliegt).

Während Sie einen ersten Durchgang durchführen können FOO1, um die Sonderzeichen für die Aufnahme in diesen sed-Befehl zu zitieren, ist die Verwendung von awk viel einfacher. Awk hat einen Variablenbegriff und eine Befehlszeilensyntax zum Festlegen des Anfangswertes einer Variablen.

awk -v FOO1="$FOO1" -v FOO2="$FOO2" -v FOO3="$FOO3" -v FOO4="$FOO4" -v FOO5="$FOO5" '{
    sub(/TMPFOO1/, FOO1);
    sub(/TMPFOO2/, FOO2);
    sub(/TMPFOO3/, FOO3);
    sub(/TMPFOO4/, FOO4);
    sub(/TMPFOO5/, FOO5);
    print;
}' /home/foo/template > /home/foo/template/finishedresult
Gilles 'SO - hör auf böse zu sein'
quelle
Trivialer Hinweis: - -vVor jeder Variablendeklaration muss a stehen.
Mike B
@ MikeB Danke für den Fehlerbericht. Im Allgemeinen bearbeiten Sie den Beitrag direkt, wenn Sie solche Tippfehler finden.
Gilles 'SO - hör auf böse zu sein'
@ Gilles Bearbeitungen von Nichtautoren müssen mindestens sechs Zeichen lang sein.
NobleUplift
6

Höchstwahrscheinlich enthält eine Ihrer $FOOVariablen Sonderzeichen, die von interpretiert werden sed.

Ich habe eine andere Version sed, die andere Fehlermeldungen generiert, aber hier ist ein Beispiel für ein ähnliches Problem:

$ VAR=a
$ echo i | sed -e "s/i/"$VAR"/"
a
$ tmp> VAR=/
$ echo i | sed -e "s/i/"$VAR"/"
sed: 1: "s/i///
": bad flag in substitute command: '/'

In diesem Fall $VARenthält ein Zeichen, das sedals abschließender Schrägstrich interpretiert wird .

Matteo
quelle
2

Wie andere hier erwähnt haben, hängt dies vom Inhalt Ihrer FOO * -Variablen ab. In Ihrem Fall ist die Verwendung seddie falsche Wahl, da sie wahrscheinlich einige Sonderzeichen enthält.

Schauen Sie sich diesen Link an und sehen Sie sich die Funktion angsub_literal

Da gsub_literalvon stdin gelesen und in stdout geschrieben wird, lautet die Verwendung:

gsub_literal "$search" "$replace" < /home/foo/template > /home/foo/template/finishedresult

Beispielausgabe:

rany$ cat > foo.txt
a'
a'

rany$ gsub_literal a\' b < foo.txt 
b
b
Rany Albeg Wein
quelle
1

Das Problem wurde für mich behoben, indem zusätzliche Backslashes innerhalb des sed 's/.../.../g'Befehls versucht wurden . Dieser Befehl

sed 's/\"a/ä/g' input_file

gab mir diese Fehlermeldung

sed: -e Ausdruck # 1, char 9: nicht abgeschlossener `s'-Befehl

wenn es als Teil eines C-Shell-Skripts ausgeführt wurde, und dies nur mit einer neueren Version von sed, nicht mit einer älteren Version. (Seltsamerweise funktioniert der gleiche Befehl einwandfrei, wenn er in der Befehlszeile (in einer TC-Shell) angegeben wird.)

Das Problem mit dem C-Shell-Skript wurde behoben, indem dem äZeichen ein Backslash vorangestellt wurde :

sed 's/\"a/\ä/g' input_file
user3346151
quelle