Почему альтернативные разделители не работают с 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.
Ошибка или функция?
Ответы
Ответ 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/.../.../
. Насколько я знаю, это только позволяет изменить разделитель команды подстановки.
В perl аналогичен. Вы можете выполнять поиск по регулярному выражению с помощью /.../
, но если вы хотите изменить разделитель, вы должны объяснить его как поиск с помощью m
, например: m|...|
.
Я предполагаю, что это будет связано с проблемой лексического разбора, но я не знаю причины.
Ответ 5
Feature. В
sed -e '/somevar/s/foo/bar/' config.h
/somevar/
является адресом. Адреса должны отличаться от других функций, таких как y
(yank), i
(insert), a
(append) и многие другие. В общем случае команды sed анализируются как
[address[,address]]function[arguments]