Enquanto:
sed "0,\~$var~s~$var~replacement~"
Pode ser usado para alterar o delimitador regex, incorporando expansões variáveis dentro do código sed (ou qualquer outro interpretador) é uma coisa muito insensata no caso geral.
Primeiro, aqui, o delimitador não é o único caractere que precisa ser escapado. Todos os operadores de expressões regulares também precisam.
Mas o mais importante, e especialmente com o GNU sed , é uma vulnerabilidade de injeção de comando. Se o conteúdo de $var não estiver sob seu controle, é tão ruim quanto passar dados arbitrários para eval .
Tente por exemplo:
$ var='^~s/.*/uname/e;#'
$ echo | sed "0,\~$var~s~$var~replacement~"
Linux
O comando uname foi executado, felizmente inofensivo ... desta vez.
As implementações não-GNU sed não podem executar comandos arbitrários, mas podem sobrescrever qualquer arquivo (com o comando w ), que é virtualmente tão ruim.
Uma maneira mais correta é escapar dos caracteres problemáticos em $var first :
NL='
'
case $var in
(*"$NL"*)
echo >&2 "Sorry, can't handle variables with newline characters"
exit 1
esac
escaped_var=$(printf '%s\n' "$var" | sed 's:[][\/.^$*]:\&:g')
# and then:
sed "0,/$escaped_var/s/$escaped_var/replacement/" < file
Outra abordagem é usar perl :
var=$var perl -pe 's/\Q$ENV{var}\E/replacement/g && $n++ unless $n' < file
Observe que não estamos expandindo o conteúdo de $var dentro do código passado para perl (que seria outra vulnerabilidade de injeção de comando), mas deixando perl expandir seu conteúdo como parte de seu processamento de regexp ( e dentro de \Q...\E , o que significa que os operadores regexp não são tratados especialmente).
Se $var contiver caracteres de nova linha, isso só poderá coincidir se houver apenas um no final. Como alternativa, pode-se passar a opção -0777 para que a entrada seja processada como um registro único em vez de linha por linha.