Как заменить строки, содержащие косые черты, на sed?

У меня есть проект Visual Studio, который разрабатывается локально. Файлы кода должны быть развернуты на удаленном сервере. Единственная проблема заключается в том, что URL содержат жестко запрограммированные URL.

Проект содержит URL-адреса, такие как ? Page = one. Чтобы ссылка действовала на сервере, она должна быть / page / one.

Я решил заменить все URL-адреса в моих кодовых файлах на sed перед развертыванием, но я застрял на слешах.

Я знаю, что это не очень хорошее решение, но оно просто сэкономит мне много времени. Общее количество строк, которые я должен заменить, меньше 10. Общее количество файлов, которые нужно проверить, составляет ~30.

Пример, описывающий мою ситуацию, приведен ниже:

Команда, которую я использую:

sed -f replace.txt < a.txt > b.txt

replace.txt, который содержит все строки:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Содержимое файла b.txt после запуска команды sed:

pageone
pagetwo
pagethree

Что я хочу, чтобы b.txt содержал:

/page/one
/page/two
/page/three

9 ответов

Решение

Самый простой способ - использовать другой разделитель в строках поиска / замены, например:

s:?page=one&:pageone:g

Вы можете использовать любой символ в качестве разделителя, который не является частью какой-либо строки. Или вы можете избежать этого с помощью обратной косой черты.

s команда может использовать любой символ в качестве разделителя; какой бы персонаж ни шел после s используется. Я был воспитан, чтобы использовать #, Вот так:

s#?page=one&#/page/one#g

Очень полезный, но менее известный факт о седе - это то, что s/foo/bar/ Команда может использовать любую пунктуацию, а не только косую черту. Общая альтернатива s@foo@bar@, из которого становится очевидным, как решить вашу проблему.

Добавить \ перед специальными символами

    s/\?page=one&/page\/one\//g

так далее

В системе, которую я разрабатываю, строка, которую нужно заменить на sed, - это вводимый пользователем текст, который сохраняется в переменной и передается в sed.

Как отмечалось ранее в этом посте, если строка, содержащаяся в командном блоке sed, содержит фактический разделитель, используемый sed - тогда sed завершается при синтаксической ошибке. Рассмотрим следующий пример:

Это работает:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Это ломает:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Замена разделителя по умолчанию не является надежным решением в моем случае, так как я не хотел ограничивать пользователя от ввода определенных символов, используемых sed в качестве разделителя (например, "/").

Тем не менее, экранирование любых вхождений разделителя во входной строке решит проблему. Рассмотрим приведенное ниже решение систематического экранирования символа-разделителя во входной строке перед его анализом с помощью sed. Такое экранирование может быть реализовано как замена с использованием самого sed, эта замена безопасна, даже если входная строка содержит разделитель - это потому, что входная строка не является частью командного блока sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

Я преобразовал это в функцию, которая будет использоваться различными сценариями:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}

Эта строка должна работать для ваших 3 примеров:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • я использовал -r чтобы спастись
  • линия должна быть общей для вашего случая один, два, три. вам не нужно делать саб 3 раза

протестируйте на своем примере (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three

sed это то, что вы можете использовать | (канал) для отправки стандартных потоков (в частности, STDIN и STDOUT) через sed и изменять их программно на лету, что делает его удобным инструментом в философской традиции Unix; но можете редактировать файлы напрямую, используя -i параметр, указанный ниже.
Учтите следующее:

sed -i -e 's/few/asd/g' hello.txt

s/ используется для замещения найденного выражения few с asd:

Немногие, смелые.


ASD, смелый.

/g расшифровывается как "глобальный", что означает сделать это для всей строки. Если вы оставите /gs/few/asd/ всегда должно быть три слэша, несмотря ни на что) и few появляется дважды на одной строке, только первый few изменено на asd:

Немногие мужчины, немногие женщины, смелые.


Asd мужчины, немногие женщины, смелые.

Это полезно в некоторых обстоятельствах, таких как изменение специальных символов в начале строк (например, замена символов "больше", которые некоторые люди используют для цитирования предыдущего материала в цепочках электронной почты, на горизонтальной табуляции, оставляя после этого цитируемое алгебраическое неравенство позже в строке нетронутым), но в вашем примере, где вы указываете, что где угодно few происходит это следует заменить, убедитесь, что у вас есть, что /g,

Следующие два параметра (флаги) объединены в один, -ie:

-i опция используется для редактирования в файле hello.txt,

-e опция указывает на выражение / команду для запуска, в этом случае s/,

Примечание: важно, чтобы вы использовали -i -e искать / заменять. Если вы делаете -ie вы создаете резервную копию каждого файла с добавленной буквой "е".

Пожалуйста , смотрите эту статью http://netjunky.net/sed-replace-path-with-slash-separators/

Просто используя | вместо того /

Отличный ответ от Anonymous. \ решил мою проблему, когда попытался экранировать кавычки в строках HTML.

Поэтому, если вы используете sed для возврата некоторых HTML-шаблонов (на сервере), используйте двойную обратную косую черту вместо одинарной:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";

replace.txt должно быть

s/?page=/\/page\//g
s/&//g

Более простой альтернативой является использование AWK, как в этом ответе:

awk '$0="prefix"$0' file > new_file

Другие вопросы по тегам