Исключить строку для шаблона замены sed

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

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

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

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

244
02 янв. '09 в 20:44
источник поделиться
14 ответов

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

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

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

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

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

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

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

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

219
24 апр. '10 в 21:35
источник

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

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

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

60
30 апр. '15 в 14:40
источник

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

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
36
02 янв. '09 в 21:31
источник

Основываясь на регулярных выражениях 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
25
06 мая '12 в 4:46
источник

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

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

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

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

12
23 янв. '14 в 20:39
источник

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

У меня был тот же вопрос и я сделал ту же ошибку. Если вы используете 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"}"
8
30 дек. '16 в 1:51
источник

Использовать 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
3
15 нояб. '14 в 2:34
источник

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

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

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

1
02 янв. '09 в 20:58
источник

Если случается, что вы генерируете случайный пароль для перехода на sed replace pattern, то вы выбираете, чтобы быть осторожным, какой набор символов в случайной строке. Если вы выберете пароль, сделанный путем кодирования значения как base64, тогда есть только символ, который возможен и в base64, а также специальный символ в шаблоне замены sed. Этот символ "/" и легко удаляется из создаваемого вами пароля:

# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;
0
01 июня '16 в 5:24
источник

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

sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test
0
01 сент. '17 в 9:35
источник

У меня есть улучшение над функцией 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.

0
30 сент. '17 в 22:41
источник

Просто удалите все в переменной REPLACE:

echo $REPLACE | awk '{gsub(".", "\\\\&");print}'
-1
02 янв. '09 в 22:03
источник

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

so (в ksh)

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"
-1
22 нояб. '13 в 18:29
источник

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

rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring  test.txt
-2
06 окт. '17 в 9:54
источник

Посмотрите другие вопросы по меткам или Задайте вопрос