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'