Ersetzen Sie eine Zeichenfolge im Shell-Skript durch eine Variable

92

Ich verwende den folgenden Code zum Ersetzen einer Zeichenfolge in einem Shell-Skript.

echo $LINE | sed -e 's/12345678/"$replace"/g'

Es wird jedoch durch $replaceanstelle des Werts dieser Variablen ersetzt.

Kann jemand sagen, was schief gelaufen ist?

Vijay
quelle
Die häufig gestellte Frage zum Umgang mit Werten mit Schrägstrichen finden Sie unter stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
Tripleee

Antworten:

142

Wenn Sie interpretieren möchten $replace, sollten Sie keine einfachen Anführungszeichen verwenden, da diese das Ersetzen von Variablen verhindern.

Versuchen:

echo $LINE | sed -e "s/12345678/\"${replace}\"/g"

Angenommen, Sie möchten die Anführungszeichen eingeben. Wenn Sie die Anführungszeichen nicht möchten, verwenden Sie:

echo $LINE | sed -e "s/12345678/${replace}/g"

Transkript:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

Achten Sie nur darauf, dass ${replace}keine Zeichen von Bedeutung sind sed(wie /zum Beispiel), da dies zu Verwirrung führen kann, wenn Sie nicht entkommen. Aber wenn Sie, wie Sie sagen, eine Nummer durch eine andere ersetzen, sollte das kein Problem sein.

paxdiablo
quelle
Ich möchte nicht, dass die Anführungszeichen eingegeben werden. Ich möchte, dass eine Zahl durch eine andere ersetzt wird
Vijay
1
paxdiablo: setist auch nicht nötig (und wie wolltest du es überhaupt benutzen?). Einfach replace=987654321.
Roman Cheplyaka
Normalerweise verwende ich immer, exportum sicherzustellen, dass Variablen für Kinder festgelegt sind, aber wie Sie sagen, können Sie dies genauso gut vermeiden. Die Verwendung oder Nichtverwendung von exportist hier jedoch irrelevant (ein Stilproblem) und hat keine Auswirkung auf die tatsächliche Antwort, dh wie Variablen innerhalb eines sedBefehls verwendet werden.
Paxdiablo
Diese Lösung scheint mit der -iOption nicht zu funktionieren . Würdest du wissen warum? oder wie soll es funktionieren?
Gabriel
1
Vielleicht weisen Sie auch darauf hin, dass für den Wechsel von einfachen zu doppelten Anführungszeichen ein $oder `im sedSkript mit einem Backslash maskiert werden muss, um es vor dem Substitutionsmechanismus der Shell für Zeichenfolgen in doppelten Anführungszeichen zu schützen.
Tripleee
73

Sie können die Shell (bash / ksh) verwenden.

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
Ghostdog74
quelle
3
Vielleicht möchten Sie erwähnen, dass dies bash-spezifisch ist (und ksh?). Wahrscheinlich nicht von Bedeutung für die meisten Menschen, aber einige von uns sind immer noch gezwungen, an alten UNIXen zu arbeiten :-)
paxdiablo
6
/bin/shBeachten Sie, dass dies auch bei Dash fehlschlägt, was bei vielen modernen Linuxes der Fall ist.
Phihag
26

Nicht spezifisch für die Frage, aber für Leute, die die gleiche Funktionalität benötigen, die aus Gründen der Klarheit gegenüber früheren Antworten erweitert wurde:

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found
Bob
quelle
8

Einfache Anführungszeichen sind sehr stark. Sobald Sie drinnen sind, können Sie nichts mehr tun, um die Variablensubstitution aufzurufen, bis Sie gehen. Verwenden Sie stattdessen doppelte Anführungszeichen:

echo $LINE | sed -e "s/12345678/$replace/g"
Dave
quelle
4
echo $LINE | sed -e 's/12345678/'$replace'/g'

Sie können weiterhin einfache Anführungszeichen verwenden, müssen diese jedoch "öffnen", wenn die Variable an der richtigen Stelle erweitert werden soll. Andernfalls wird die Zeichenfolge "wörtlich" genommen (wie @paxdiablo richtig angegeben hat, ist auch seine Antwort richtig).

Akira
quelle
Dies hat das Problem, dass die Verwendung $replaceaußerhalb von Anführungszeichen dazu führt, dass die Shell eine Whitespace-Tokenisierung und eine Platzhaltererweiterung für den Wert durchführt. Dies scheint mit einfachen Werten zu funktionieren, kann jedoch bei nicht trivialen Zeichenfolgen dramatisch explodieren. Verwenden Sie dies nicht im Produktionscode.
Tripleee
2

Damit Ihre Shell die Variable erweitern kann, müssen Sie doppelte Anführungszeichen wie verwenden

sed -i "s#12345678#$replace#g" file.txt

Dies wird unterbrochen, wenn $replaceSonderzeichen sed( #, \) enthalten sind. Sie können sie jedoch vorverarbeiten $replace, um sie zu zitieren:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt
Matthieu Moy
quelle
0

Ich hatte eine ähnliche Anforderung, aber mein Ersatz-Var enthielt ein kaufmännisches Und. Wenn ich dem kaufmännischen Und so entkommen konnte, löste sich mein Problem:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"
Richard Salt
quelle
-1

Verwenden Sie dies stattdessen

echo $LINE | sed -e 's/12345678/$replace/g'

Das funktioniert bei mir einfach die Anführungszeichen entfernen

Tunde Pizzle
quelle
-2

Ich bevorzuge doppelte Anführungszeichen, da einfache Quptes sehr mächtig sind, da wir sie verwenden, wenn sie nichts darin ändern oder die variable Substitution aufrufen können.

Verwenden Sie daher doppelte Anführungszeichen.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
quelle
6
Unterscheidet sich das von Daves Antwort ?
devnull