Você precisará escapar de todos os caracteres especiais em expressões regulares, não apenas barras invertidas, mas também [.*^$
e s
delimitador (para sed). Em Perl, use a função quotemeta
.
Um outro problema com sua tentativa é que quando você executa set -- $line
, o shell executa sua própria expansão: ele executa globbing além da divisão de palavras, portanto, se sua linha contiver a* b*
e houver arquivos chamados a1
e a2
no diretório atual, então você substituirá a1
por a2
. Você precisa desativar o globbing com set -f
nessa abordagem.
Aqui está uma solução que manipula a lista de substituição diretamente em uma lista de argumentos do sed. Ele pressupõe que não há nenhum caractere de espaço nos textos de origem e de substituição, mas qualquer outra coisa que não seja um espaço e uma nova linha deve ser tratada corretamente. A primeira substituição adiciona \
antes dos caracteres que precisam ser protegidos, e a segunda substituição transforma cada linha de foo bar
em -e s/foo/bar/g
. Atenção, não testado.
set -f
sed_args=$(<replacement sed -e 's~[/.*[\^$]~\&~g' \
-e 's~^\([^ ]*\) *\([^ ]*\).*~-e s///g~')
sed -i $sed_args target
Em Perl, você terá menos problemas com aspas, se você apenas permitir que Perl leia o arquivo de substituição diretamente. Mais uma vez, não testado.
perl -i -pe 'BEGIN {
open R, "<replacement" or die;
while (<R>) {
chomp;
($from, $to, @ignored) = split / +/;
$s{$from} = $to;
}
close R;
$regexp = join("|", map {quotemeta} keys %s);
}
s/($regexp)/$s{$1}/ego'