Substitua uma string no script de shell usando uma variável

93

Estou usando o código abaixo para substituir uma string dentro de um script de shell.

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

mas está sendo substituído em $replacevez do valor dessa variável.

Alguém poderia dizer o que deu errado?

Vijay
fonte
Para a pergunta comum relacionada sobre como lidar com valores com barras, consulte stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Respostas:

146

Se você quiser interpretar $replace, não deve usar aspas simples, pois elas evitam a substituição de variáveis.

Experimentar:

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

presumindo que você deseja que as aspas sejam inseridas. Se não quiser as aspas, use:

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

Transcrição:

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

Apenas tome cuidado para garantir que ${replace}não tenha nenhum caractere significativo para sed(como /por exemplo), uma vez que causará confusão, a menos que seja escapado. Mas se, como você diz, está substituindo um número por outro, isso não deve ser um problema.

paxdiablo
fonte
não quero que as aspas sejam colocadas. Quero que um número seja substituído por outro
Vijay
1
paxdiablo: settambém não é necessário (e como você iria usá-lo?). Apenas replace=987654321.
Roman Cheplyaka
Normalmente sempre costumo exportgarantir que as variáveis ​​sejam definidas para crianças, mas, como você disse, você poderia facilmente evitá-lo. No entanto, o uso ou não de exporté irrelevante aqui (uma questão de estilo) e não tem efeito na resposta real, que é como usar variáveis ​​em um sedcomando.
paxdiablo
Esta solução não parece funcionar com a -iopção. Você saberia por quê? ou como fazer funcionar?
Gabriel
1
Talvez também aponte que a mudança de aspas simples para duplas requer que qualquer $ou `no sedscript seja escapado com uma barra invertida, para protegê-lo do mecanismo de substituição do shell para strings entre aspas duplas.
tripleee
73

você pode usar o shell (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
ghostdog74
fonte
3
Pode querer mencionar que é específico do bash (e ksh?). Provavelmente não de importação para a maioria das pessoas, mas alguns de nós ainda são forçados a trabalhar no antigo UNIXen :-)
paxdiablo
6
Cuidado, isso também falha no painel, que está /bin/shem muitos Linuxes modernos.
phihag 02 de
26

Não é específico para a pergunta, mas para pessoas que precisam do mesmo tipo de funcionalidade expandida para maior clareza a partir das respostas 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
prumo
fonte
8

As aspas simples são muito fortes. Uma vez dentro, não há nada que você possa fazer para invocar a substituição de variável, até que você saia. Em vez disso, use aspas duplas:

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

você ainda pode usar aspas simples, mas tem que "abri-las" quando quiser que a variável seja expandida no lugar certo. caso contrário, a string é interpretada "literalmente" (como @paxdiablo afirmou corretamente, sua resposta também está correta)

Akira
fonte
Isso tem o problema de que o uso de $replacefora de quaisquer aspas fará com que o shell execute a tokenização de espaço em branco e a expansão de curinga no valor. Isso parecerá funcionar com valores simples, mas pode explodir dramaticamente em strings não triviais. Não use isso no código de produção.
tripleee
2

Para permitir que seu shell expanda a variável, você precisa usar aspas duplas, como

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

Isso será interrompido se $replacecontiver sedcaracteres especiais ( #, \). Mas você pode pré $replace- processar para citá-los:

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

Eu tinha um requisito semelhante a este, mas minha substituição var continha um E comercial. O escape do "e" comercial desta forma resolveu meu problema:

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

Use isto ao invés

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

Isso funciona para mim simplesmente remover as aspas

Tunde Pizzle
fonte
-2

Eu prefiro usar aspas duplas, já que quptes simples são muito poderosos, já que os usamos se não pudéssemos mudar nada dentro deles ou poderíamos invocar a substituição da variável.

então use aspas duplas instaladas.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
fonte
6
Isso é diferente da resposta de Dave ?
devnull