Подтвердить что ты не робот

Почему альтернативные разделители не работают с sed -e '/pattern/s/a/b/'?

Вот что я обнаружил, что не имеет смысла.

Вывод cat config.h:

define somevar foo // Sample variable

Эта версия команды работает для изменения foo на bar и сохранения комментариев:

sed -e '/somevar/s/foo/bar/' config.h

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

sed -e '|somevar|s|foo|bar|' config.h

Дает эту ошибку:

sed: -e выражение # 1, char 1: неизвестная команда: `| '

Как ни странно, это работает:

sed -e '/somevar/s|foo|bar|' config.h

Возможно, мне не хватает части документации. Кажется очень странным иметь два разных разделителя в одной команде sed.

Ошибка или функция?

4b9b3361

Ответ 1

Это будет работать:

sed -e '\|somevar|s|foo|bar|'

Страница man файла GNU sed довольно понятна:

   /regexp/
          Match lines matching the regular expression regexp.

   \cregexpc
          Match lines matching the regular expression regexp.  The  c  may
          be any character.

То есть, c может быть любым символом, но начальный \ является обязательным.

У меня нет FreeBSD, но в соответствии с @bonsaiviking страница man также очень понятна:

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

С другой стороны, в OSX это неясно:

      In a context address, any character other than a backslash (``\'')
      or newline character may be used to delimit the regular expression.
      Also, putting a backslash character before the delimiting character
      causes the character to be treated literally.  For example, in the
      context address \xabc\xdefx, the RE delimiter is an ``x'' and the
      second ``x'' stands for itself, so that the regular expression is
      ``abcxdef''.

Обратите внимание, что в этом примере используется \xpatternx вместо xpatternx. Что все это дает ключ, он не дает понять, что xpatternx не будет работать.

Основываясь на аргументе @that-other-guy, имеет смысл, что sed (и другие языки, такие как perl как @Birei указал, что этот дополнительный ключ должен работать правильно.

Ответ 2

Разрешение различных разделителей для /pattern/ приведет к неоднозначности разбора.

Может ли ispaghetti быть как /spaghett/, или он должен вставлять текст как i spaghetti?

С s и y такой двусмысленности нет. Когда вы видите любой из этих символов, вы знаете команду, которую вы читаете, а затем вы можете интерпретировать следующий символ как разделитель.

Мы могли бы устранить эту двусмысленность для /pattern/, если бы мы запустили ее с аналогично узнаваемым символом, и действительно, у sed есть отдельный спецификатор адреса для этого: обратная косая черта, как в \|pattern| (это не то же самое, что экранирование).

Поэтому мы можем написать \|pattern|s|foo|bar|.

Команды адреса и редактирования являются отдельными, поэтому \$pattern$s_foo_bar_ и /pattern/s#foo#bar# работают.

Ответ 3

Вы можете использовать альтернативные разделители для соответствующего адреса (/regex/), но вам нужно сообщить sed, что вы намерены выполнить сопоставление с этим разделителем. То, как вы это делаете, - с помощью обратного слэша \. Таким образом, ваша команда может быть:

sed -e '\|somevar|s|foo|bar|' config.h

или так же легко:

sed -e '\%somevar%s|foo|bar|' config.h

Ссылка: Ссылка POSIX для sed

Ответ 4

Мое голосование за функцию.

Это две разные команды: поисковый /.../ и подстановочный, s/.../.../. Насколько я знаю, это только позволяет изменить разделитель команды подстановки.

В аналогичен. Вы можете выполнять поиск по регулярному выражению с помощью /.../, но если вы хотите изменить разделитель, вы должны объяснить его как поиск с помощью m, например: m|...|.

Я предполагаю, что это будет связано с проблемой лексического разбора, но я не знаю причины.

Ответ 5

Feature. В

 sed -e '/somevar/s/foo/bar/' config.h

/somevar/ является адресом. Адреса должны отличаться от других функций, таких как y (yank), i (insert), a (append) и многие другие. В общем случае команды sed анализируются как

 [address[,address]]function[arguments]