Экранирование строки для шаблона замены sed

StackOverflow https://stackoverflow.com/questions/407523

  •  03-07-2019
  •  | 
  •  

Вопрос

В моем сценарии bash у меня есть внешняя (полученная от пользователя) строка, которую я должен использовать в шаблоне sed.

REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"

Как я могу избежать $REPLACE строка, чтобы она была безопасно принята sed в качестве буквальной замены?

ПРИМЕЧАНИЕ: А KEYWORD это тупая подстрока без совпадений и т. д.Он не предоставляется пользователем.

Это было полезно?

Решение

Предупреждение:Это делает нет рассмотрите новые строки.Более подробный ответ см. этот SO-вопрос вместо.(Спасибо, Эд Мортон и Никлас Питер)

Обратите внимание, что избегать всего — плохая идея.Седу нужно, чтобы много символов было экранировано. получать их особое значение.Например, если вы экранируете цифру в строке замены, она превратится в обратную ссылку.

Как сказал Бен Бланк, в строке замены необходимо экранировать только три символа (сами экранируются, косая черта для конца оператора и & для замены всех):

sed -e 's/[\/&]/\\&/g'

Если вам когда-нибудь понадобится сбежать из KEYWORD строка, вам нужна следующая:

sed -e 's/[]\/$*.^[]/\\&/g'

Помните, что если вы используете символ, отличный от / в качестве разделителя вам нужно заменить косую черту в приведенных выше выражениях на используемый вами символ.См. комментарий PeterJCLaw для объяснения.

Отредактировано: Из-за некоторых необычных случаев, которые ранее не учитывались, приведенные выше команды менялись несколько раз.Подробности смотрите в истории изменений.

Другие советы

Команда sed позволяет использовать другие символы вместо / в качестве разделителя:

sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'

Двойные кавычки не являются проблемой.

Единственные три буквальных символа, которые обрабатываются особым образом в предложении замены, — это / (чтобы закрыть пункт), \ (чтобы экранировать символы, обратную ссылку и т. д.) и & (чтобы включить совпадение в замену).Поэтому все, что вам нужно сделать, это экранировать эти три символа:

sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"

Пример:

$ export REPLACE="'\"|\\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
foo'"|\/><&!bar

На основе регулярных выражений Pianosaurus я создал функцию bash, которая экранирует как ключевое слово, так и замену.

function sedeasy {
  sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
}

Вот как вы его используете:

sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf

Немного поздно отвечать...но есть гораздо более простой способ сделать это.Просто измените разделитель (т. е. символ, разделяющий поля).Итак, вместо s/foo/bar/ ты пишешь s|bar|foo.

И вот простой способ сделать это:

sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g'

Полученный результат лишен этого неприятного предложения DEFINER.

Оказывается, вы задаете неправильный вопрос.Я тоже задал неправильный вопрос.Причиной неправильности является начало первого предложения:"В моем бить сценарий...".

У меня был тот же вопрос и я сделал ту же ошибку.Если вы используете bash, вам не нужно использовать sed для замены строк (и это много очиститель, чтобы использовать функцию замены, встроенную в bash).

Вместо чего-то вроде:

function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A="$(escape-all-funny-characters 'KEYWORD')"
B="$(escape-all-funny-characters '<funny characters here>')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"

вы можете использовать исключительно функции bash:

INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"

Используйте awk — это чище:

$ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare

Вот пример AWK, который я использовал некоторое время назад.Это AWK, который печатает новые AWKS.Поскольку AWK и SED схожи, это может быть хорошим шаблоном.

ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds

Это выглядит чрезмерным, но каким-то образом эта комбинация кавычек позволяет сохранить ' как литералы.Тогда, если я правильно помню, доступные просто заключаются в такие кавычки:«1 доллар».Попробуйте, дайте мне знать, как это работает с SED.

У меня есть улучшение по сравнению с функцией sedeasy, которая БУДЕТ ломаться со специальными символами, такими как табуляция.

function sedeasy_improved {
    sed -i "s/$(
        echo "$1" | sed -e 's/\([[\/.*]\|\]\)/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/$(
        echo "$2" | sed -e 's/[\/&]/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/g" "$3"
}

Итак, что же отличается? $1 и $2 заключены в кавычки, чтобы избежать расширения оболочки и сохранить табуляцию или двойные пробелы.

Дополнительные трубопроводы | sed -e 's:\t:\\t:g' (Мне нравится : как токен), который преобразует вкладку в \t.

не забывайте обо всех удовольствиях, которые возникают при ограничении оболочки вокруг " и '

итак (в кш)

Var=">New version of \"content' here <"
printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar

echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"

Если случается так, что вы генерируете случайный пароль для перехода к sed заменить шаблон, тогда вам следует внимательно выбирать набор символов в случайной строке.Если вы выберете пароль, созданный путем кодирования значения в формате Base64, то будет только один символ, который возможен как в Base64, так и в качестве специального символа в sed заменить шаблон.Этот символ — «/» и его легко удалить из генерируемого пароля:

# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;

Если вы просто хотите заменить значение переменной в команде SED, просто удалите пример:

sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test

Более простой способ сделать это — заранее создать строку и использовать ее в качестве параметра для sed

rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring  test.txt
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top