Para escapar de variáveis a serem usadas no lado esquerdo e no lado direito de um comando s em sed (aqui $lhs e $rhs respectivamente), você faria:
escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')
sed "s/$escaped_lhs/$escaped_rhs/"
Observe que $lhs não pode conter um caractere de nova linha.
Ou seja, no LHS, escape de todos os operadores regexp ( ][.^$* ), do próprio caractere de escape ( \ ) e do separador ( / ).
No RHS, você só precisa escapar de & , o separador, a barra invertida e o caractere de nova linha (o que você faz inserindo uma barra invertida no final de cada linha, exceto a última ( $!s/$/\/ )). / p>
Isso pressupõe que você use / como separador nos comandos sed s e que você não habilita REs estendidos com -r (GNU sed / ssed / ast / busybox sed ) ou -E (BSDs, ast , GNU recente, busybox recente) ou PCREs com -R ( ssed ) ou Aumentada REs com -A / -X ( ast ), todos com operadores RE extras.
Algumas regras básicas ao lidar com dados arbitrários:
- Não use
echo - cite suas variáveis
- considere o impacto da localidade (especialmente seu conjunto de caracteres: é importante que os comandos escape
sedsejam executados na mesma localidade que o comandosedusando escapou strings (e com o mesmo comandosed) por exemplo) - não se esqueça do caractere de nova linha (aqui você pode querer verificar se
$lhscontém algum e executar uma ação).
Outra opção é usar perl em vez de sed e passar as strings no ambiente e usar os operadores \Q / \E perl regexp para obter strings literalmente:
A=lhs B=rhs perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl (por padrão) não será afetado pelo conjunto de caracteres do local, pois, acima, considera apenas as cadeias como matrizes de bytes sem se importar com quais caracteres (se houver) eles podem representar para o usuário. Com sed , você pode conseguir o mesmo, fixando a localidade em C com LC_ALL=C para todos os comandos sed (embora isso também afete o idioma das mensagens de erro, se houver).