Remplacer une chaîne dans le script shell à l'aide d'une variable

93

J'utilise le code ci-dessous pour remplacer une chaîne dans un script shell.

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

mais il est remplacé par $replaceau lieu de la valeur de cette variable.

Quelqu'un pourrait-il dire ce qui n'a pas fonctionné?

Vijay
la source
Pour la question connexe commune sur la gestion des valeurs avec des barres obliques, voir stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Réponses:

146

Si vous souhaitez interpréter $replace, vous ne devez pas utiliser de guillemets simples car ils empêchent la substitution de variables.

Essayer:

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

en supposant que vous vouliez insérer les guillemets. Si vous ne voulez pas les guillemets, utilisez:

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

Transcription:

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

Veillez simplement à ce ${replace}qu'il n'y ait aucun caractère significatif pour sed(comme /par exemple) car cela causera de la confusion à moins d'être échappé. Mais si, comme vous le dites, vous remplacez un numéro par un autre, cela ne devrait pas poser de problème.

paxdiablo
la source
Je ne veux pas que les guillemets soient mis, je veux qu'un numéro soit remplacé par un autre
Vijay
1
paxdiablo: setn'est pas non plus nécessaire (et comment alliez-vous l'utiliser de toute façon?). Juste replace=987654321.
Roman Cheplyaka
J'utilise généralement toujours exportpour m'assurer que les variables sont définies pour les enfants mais, comme vous le dites, vous pouvez tout aussi bien l'éviter. Cependant, l'utilisation ou non de exportn'est pas pertinente ici (un problème de style) et n'a aucun effet sur la réponse réelle, à savoir comment utiliser des variables dans une sedcommande.
paxdiablo
Cette solution ne semble pas fonctionner avec l' -ioption. Savez-vous pourquoi? ou comment le faire fonctionner?
Gabriel
1
Peut-être aussi souligner que le passage des guillemets simples aux guillemets doubles nécessite que tout $ou `dans le sedscript soit échappé avec une barre oblique inverse, pour le protéger du mécanisme de substitution du shell pour les chaînes entre guillemets.
tripleee
73

vous pouvez utiliser le shell (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
ghostdog74
la source
3
Vous voudrez peut-être mentionner que c'est spécifique à bash (et ksh?). Probablement pas important pour la plupart des gens, mais certains d'entre nous sont encore obligés de travailler sur l'ancien UNIXen :-)
paxdiablo
6
Attention, cela échoue également sur le tableau de bord, qui est /bin/shsur de nombreux Linux modernes.
phihag
26

Pas spécifique à la question, mais pour les personnes qui ont besoin du même type de fonctionnalité étendue pour plus de clarté par rapport aux réponses précédentes:

# 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
la source
8

Les guillemets simples sont très forts. Une fois à l'intérieur, vous ne pouvez rien faire pour invoquer la substitution de variable, jusqu'à ce que vous quittiez. Utilisez plutôt des guillemets doubles:

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

vous pouvez toujours utiliser des guillemets simples, mais vous devez les «ouvrir» lorsque vous voulez que la variable soit développée au bon endroit. sinon la chaîne est prise "littéralement" (comme @paxdiablo l'a correctement indiqué, sa réponse est également correcte)

Akira
la source
Cela pose le problème que l'utilisation en $replacedehors des guillemets entraînera la création de jetons d'espaces blancs et l'extension de caractères génériques par le shell sur la valeur. Cela semblera fonctionner avec des valeurs simples, mais pourrait exploser considérablement sur des chaînes non triviales. Ne l'utilisez pas dans le code de production.
tripleee
2

Pour laisser votre shell développer la variable, vous devez utiliser des guillemets doubles comme

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

Cela se cassera si $replacecontiennent des sedcaractères spéciaux ( #, \). Mais vous pouvez prétraiter $replacepour les citer:

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

J'avais une exigence similaire à celle-ci, mais mon var de remplacement contenait une esperluette. Échapper à l'esperluette comme ceci a résolu mon problème:

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

Utilisez plutôt ceci

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

cela fonctionne pour moi, supprimez simplement les guillemets

Tunde Pizzle
la source
-2

Je préfère utiliser des guillemets doubles, car les quptes simples sont très puissants car nous les avons utilisés si nous ne pouvons rien changer à l'intérieur ou si nous pouvons invoquer la substitution de variable.

utilisez donc des guillemets doubles.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
la source
6
Est-ce différent de la réponse de Dave ?
devnull