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

11

Например
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
, я должен экранировать символы, чтобы сформировать регулярное выражение. В этом случае мне пришлось избегать скобок, чтобы их можно было интерпретировать несколько раз.
Почему? Я ожидал, что все будет символом регулярного выражения, если не сбежит. Т.е. наоборот.

Джим
источник
Был пост о поиске в Vim, который несколько освещает этот вопрос, краткая версия которого «это зависит от реализации команды» ... unix.stackexchange.com/questions/90345/…
Драв Слоан
@DravSloan: Я не уверен, что это то же самое. В Vim вы ищете текст по умолчанию, и вам нужно бежать, чтобы найти регулярное выражение. Но в этом случае формат s/regex//gуже ожидает регулярное выражение, и я ожидаю, что это текст, который будет нуждаться в чтобы избежать
Джим

Ответы:

14

Это связано с тем, что sedиспользуются POSIX BRE (базовые регулярные выражения) в отличие от ERE (расширенных регулярных выражений), к которым вы, вероятно, привыкли из Perl или друзей.

Со sed(1)страницы руководства :

REGULAR EXPRESSIONS
       POSIX.2 BREs should be supported, but they aren't completely because of
       performance problems.  The \n sequence in a regular expression  matches
       the newline character, and similarly for \a, \t, and other sequences.

Соответствующая цитата по вышеуказанной ссылке:

Вариант Basic Regular Expressions или BRE стандартизирует вариант, аналогичный тому, который используется традиционной командой UNIX grep. Это в значительной степени самый старый из регулярных выражений, который до сих пор используется. Одна вещь, которая выделяет этот аромат, состоит в том, что большинству метасимволов требуется обратный слеш, чтобы придать метасимволу его вкус. Большинство других разновидностей, включая POSIX ERE, используют обратную косую черту для подавления значения метасимволов.

Цитируется дословно из комментария Крейга Сандерса :

Обратите внимание, что по крайней мере в GNU sed вы можете указать sed использовать расширенные регулярные выражения с параметром командной строки -r или --regexp-extended. Это полезно, если вы хотите избежать чрезмерного экранирования сценария sed.

Джозеф Р.
источник
1
Обратите внимание, что по крайней мере в GNU sed вы можете указать sed использовать расширенные регулярные выражения с параметром -rили --regexp-extendedкомандной строки. Это полезно, если вы хотите избежать чрезмерного экранирования сценария sed.
Cas
@CraigSanders Спасибо за это. Добавлено в ответ.
Джозеф Р.
@CraigSanders, другие sedреализации (когда они поддерживают ERE, в основном BSD) -Eвместо этого, как правило, используют для этого (что имеет гораздо больше смысла, поскольку это тот же вариант, что и для grep. Почему GNU sedвыбрал -r, для меня загадка).
Стефан Шазелас
да, для меня загадка тоже Было бы больше смысла использовать -E. и затем добавьте -F, -G и -P, чтобы соответствовать GNU grep. IMO gawk тоже выиграет от тех же аргументов RE ... или, по крайней мере, -P.
КАС
12

Это по историческим причинам.

Regexp были впервые представлены в Unix в edутилите в начале 70-х годов. Хотя edбыл основан на qedосуществление которых по тем же авторов понимается более сложное регулярное выражение, edтолько понял ^, $, [...], ., *и , \чтобы избежать всего вышеперечисленного.

Теперь, когда возникла необходимость иметь больше операторов, нужно было найти способ представить их без нарушения обратной совместимости. Если скрипт , используемый , чтобы использовать s edкоманду , как s/foo() {/foo (var) {/gзаменить все экземпляры foo() {с , foo(var) { и вы ввели (или {оператора, что бы разорвать этот сценарий.

Однако ни один скрипт не подойдет s/foo\(\) {/foo\(var\) {/, потому что это так же, как s/foo() {/foo(var) {/и не было никаких причин сбегать, (поскольку это не оператор RE. Таким образом, введение нового оператора \(или \{оператора не нарушает обратную совместимость, поскольку очень маловероятно, что существующий сценарий нарушит старый синтаксис.

Итак, вот что было сделано. Позже, \(...\)был добавлен изначально только для s edкоманды, чтобы сделать что-то вроде, s/foo\(.\)/\1bar/а позже как grep '\(.\)\1'(но не так, как \(xx\)*).

В UnixV7 (1979 год, то есть почти десятилетие спустя) в новую и регулярные выражения были добавлены новая форма регулярных выражений egrepи awkутилиты, называемые расширенными регулярными выражениями (поскольку они являются новыми инструментами, обратной совместимости нарушать нельзя). Наконец, он предоставил функциональность, доступную в древнем Кене Томпсоне qed(оператор чередования |, группировка (..)*), и добавил несколько операторов, таких как +и ?(но не имел функции обратной ссылки в основных регулярных выражениях).

Позже BSD добавили \<и \>(и к BRE, и к ERE), а SysV добавили \{и \}только к BRE.

Это не намного позже {и }были добавлены в ERE, из-за такой нарушения обратной совместимости. Не все это добавили. Например, GNU awkдо версии 4.0.0 (2011) не поддерживала, {пока не была переведена в режим соответствия POSIX.

когда GNU grepбыл написан в начале 90-х, он добавил все вкусности от BSD и SysV (вроде \<, {), и вместо того, чтобы иметь два отдельных синтаксиса regexp и механизм для BRE и ERE, реализовал одинаковые операторы в обоих, только аналоги BRE (, ?, {, +должны предшествовать с обратной косой черты (чтобы быть совместимым с другими реализациями BRE). Вот почему вы можете делать это .\+в GNU grep(хотя это не POSIX или не поддерживается другими реализациями), и вы можете делать это (.)\1в GNU egrep(хотя это не POSIX или не поддерживается многими другими реализациями, включая GNU awk).

Добавление \xоператоров - не единственный способ добавить больше операторов в обратно совместимом виде. Например, perlиспользуется (?...). Это все еще обратно совместимо с ERE, что (?=...)недопустимо в ERE, то же самое для .*?. vimдля аналогичных операторов сделал это по-другому, введя \@=или, .\{-}например.

Стефан Шазелас
источник