Чтобы экранировать переменные, которые будут использоваться в левой и правой частях 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
perl
regexp для буквального восприятия строк:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl
(по умолчанию) не будет зависеть от набора символов локали, так как в приведенном выше примере он рассматривает только строки как массивы байтов, не заботясь о том, какие символы (если они есть) они могут представлять для пользователя. С помощью sed
этого вы можете добиться того же, установив локаль в C
with LC_ALL=C
для всех sed
команд (хотя это также повлияет на язык сообщений об ошибках, если таковые имеются).