Reemplazar una cadena en un script de shell usando una variable

93

Estoy usando el siguiente código para reemplazar una cadena dentro de un script de shell.

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

pero se reemplaza con en $replacelugar del valor de esa variable.

¿Alguien podría decir qué salió mal?

Vijay
fuente
Para la pregunta relacionada común sobre el manejo de valores con barras inclinadas, consulte stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Respuestas:

146

Si desea interpretar $replace, no debe utilizar comillas simples, ya que impiden la sustitución de variables.

Tratar:

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

asumiendo que desea incluir las comillas. Si no desea las comillas, utilice:

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

Transcripción:

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

Solo tenga cuidado de asegurarse de que ${replace}no tenga ningún carácter significativo para sed(como /por ejemplo), ya que causará confusión a menos que se escape. Pero si, como dice, está reemplazando un número por otro, eso no debería ser un problema.

paxdiablo
fuente
No quiero que se pongan las comillas. Quiero que un número sea reemplazado por otro
Vijay
1
paxdiablo: settampoco es necesario (¿y cómo lo ibas a usar de todos modos?). Solo replace=987654321.
Roman Cheplyaka
Por lo general, siempre lo uso exportpara asegurarme de que las variables estén configuradas para niños, pero, como usted dice, podría evitarlo fácilmente. Sin embargo, el uso o no de exportes irrelevante aquí (un problema de estilo) y no tiene ningún efecto en la respuesta real, que es cómo usar las variables dentro de un sedcomando.
paxdiablo
Esta solución no parece funcionar con la -iopción. ¿Sabrías por qué? o como hacerlo funcionar?
Gabriel
1
Tal vez también señale que cambiar de comillas simples a dobles requiere que se escapen cualquiera $o `en el sedscript con una barra invertida, para protegerlo del mecanismo de sustitución del shell por cadenas entre comillas dobles.
tripleee
73

puede usar el shell (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
ghostdog74
fuente
3
Quizás desee mencionar que es específico de bash (¿y ksh?). Probablemente no sea de importancia para la mayoría de la gente, pero algunos de nosotros todavía estamos obligados a trabajar en UNIXen antiguo :-)
paxdiablo
6
Tenga cuidado, esto también falla en el tablero, que se encuentra /bin/shen muchos Linux modernos.
phihag
26

No es específico de la pregunta, pero para las personas que necesitan el mismo tipo de funcionalidad ampliada para mayor claridad de las respuestas anteriores:

# 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
Beto
fuente
8

Las comillas simples son muy fuertes. Una vez dentro, no hay nada que pueda hacer para invocar la sustitución de variables, hasta que se vaya. En su lugar, utilice comillas dobles:

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

aún puede usar comillas simples, pero tiene que "abrirlas" cuando desee que la variable se expanda en el lugar correcto. de lo contrario, la cadena se toma "literalmente" (como @paxdiablo dijo correctamente, su respuesta también es correcta)

Akira
fuente
Esto tiene el problema de que el uso $replacefuera de las comillas hará que el shell realice la tokenización de espacios en blanco y la expansión de comodines en el valor. Esto parecerá funcionar con valores simples, pero podría explotar dramáticamente en cadenas no triviales. No use esto en el código de producción.
tripleee
2

Para permitir que su shell expanda la variable, debe usar comillas dobles como

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

Esto se romperá si $replacecontiene sedcaracteres especiales ( #, \). Pero puede preprocesarlos $replacepara citarlos:

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

Tenía un requisito similar a este, pero mi var de reemplazo contenía un ampersand. Escapar del ampersand como este resolvió mi problema:

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

Usa esto en su lugar

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

esto funciona para mí simplemente quita las comillas

Tunde Pizzle
fuente
-2

Prefiero usar comillas dobles, ya que los quptes simples son muy poderosos ya que los usamos si no podemos cambiar nada dentro de ellos o podemos invocar la sustitución de variables.

así que use comillas dobles instaladas.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
fuente
6
¿Es esto diferente a la respuesta de Dave ?
devnull