Para escapar das variáveis a serem usadas no lado esquerdo e no lado direito de um s
comando sed
(aqui $lhs
e $rhs
respectivamente), faça o seguinte:
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 todos os operadores regexp ( ][.^$*
), o próprio caractere de escape ( \
) e o separador ( /
).
No RHS, você só precisa escapar &
, 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/$/\\/
)).
Isso pressupõe que você use /
como separador em seus sed
s
comandos e que não ative REs estendidas com -r
(GNU sed
/ ssed
/ ast
/ busybox sed
) ou -E
(BSDs, ast
GNU recente, busybox recente) ou PCREs com -R
( ssed
) ou REs aumentadas com -A
/ -X
( ast
) que todos têm operadores extras de ER.
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 de escape
sed
sejam executados no mesmo local que o sed
comando usando as seqüências de escape (e com o mesmo sed
comando) por exemplo)
- não se esqueça do caractere de nova linha (aqui você pode verificar se
$lhs
contém algum e executar uma ação).
Outra opção é usar em perl
vez de sed
e passar as strings no ambiente e usar os operadores \Q
/ \E
perl
regexp para interpretar as 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 da localidade, pois, acima, ela considera apenas as cadeias de caracteres como matrizes de bytes sem se preocupar com os caracteres (se houver) que eles podem representar para o usuário. Com sed
, você pode conseguir o mesmo fixando o código do idioma C
com LC_ALL=C
para todos os sed
comandos (embora isso também afete o idioma das mensagens de erro, se houver).