Чтобы экранировать переменные, которые будут использоваться в левой и правой частях sкоманды sed(здесь $lhsи $rhsсоответственно), вы должны сделать:
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/"
Обратите внимание, что $lhsне может содержать символ новой строки.
То есть на LHS экранируют все операторы регулярных выражений ( ][.^$*), сам экранирующий символ ( \) и разделитель ( /).
На RHS вам нужно только экранировать &, разделитель, обратную косую черту и символ новой строки (что вы делаете, вставляя обратную косую черту в конце каждой строки, кроме последней ( $!s/$/\\/)).
Это предполагает, что вы используете /в качестве разделителя в своих sed sкомандах и что вы не включаете расширенные RE с -r(GNU sed/ ssed/ ast/ busybox sed) или -E(BSD ast, недавний GNU, недавний busybox) или PCRE с -R( ssed) или дополненные RE с -A/ -X( ast), которые у всех есть дополнительные операторы RE.
Несколько основных правил при работе с произвольными данными:
- Не использовать
echo
- процитируйте свои переменные
- рассмотреть влияние локали (особенно ее набора символов: важно, чтобы экранирующие
sed команды выполнялись в той же локали, что и sedкоманда, например, с использованием экранированных строк (и с той же sedкомандой))
- не забывайте о символе перевода строки (здесь вы можете проверить, есть ли в
$lhsнем символ, и принять меры).
Другой вариант - использовать perlвместо sedи передавать строки в среде и использовать операторы \Q/ \E perlregexp для буквального восприятия строк:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl(по умолчанию) не будет зависеть от набора символов локали, так как в приведенном выше примере он рассматривает только строки как массивы байтов, не заботясь о том, какие символы (если они есть) они могут представлять для пользователя. С помощью sedэтого вы можете добиться того же, установив локаль в Cwith LC_ALL=Cдля всех sedкоманд (хотя это также повлияет на язык сообщений об ошибках, если таковые имеются).