Ответы:
Это как ?
во многих других механизмах регулярных выражений, и означает «соответствовать нулю или одному из того, что было до него».
В вашем примере, объект \?
применяется к [ -]
, то есть он пытается найти пробел или минус, но пробел или минус необязателен.
Таким образом, любой из них будет соответствовать:
555 1234
555-1234
5551234
Причина написана как \?
а не ?
для обратной совместимости.
Оригинальная версия grep
использовала другой тип регулярного выражения, называемого «базовое регулярное выражение», где?
просто означало буквальный знак вопроса.
Чтобы GNU grep мог иметь нулевую или одну функциональность, они добавили его, но должны были использовать \?
синтаксис, чтобы скрипты, которые использовали?
работали, как и ожидалось.
Обратите внимание, что grep имеет -E
опция, которая заставляет его использовать более распространенный тип регулярных выражений, называемый «расширенные регулярные выражения».
man 1 grep
:
-E, --extended-regexp
Interpret PATTERN as an extended regular expression
(ERE, see below). (-E is specified by POSIX.)
-G, --basic-regexp
Interpret PATTERN as a basic regular expression (BRE, see below).
This is the default.
...
Repetition
A regular expression may be followed by one of several repetition operators:
? The preceding item is optional and matched at most once.
...
grep understands three different versions of regular expression syntax:
“basic,” “extended” and “perl.”
...
Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and )
lose their special meaning; instead use the backslashed versions
\?, \+, \{, \|, \(, and \).
Дополнительная информация:
grep -E
это официальный способ POSIX. egrep
устарел в susv2 (1997) и удален в susv3 (2001) из спецификаций POSIX и Unix.
\?
это GNUism, хотя.
К сожалению, точный синтаксис регулярных выражений немного различается в разных программах: регулярные выражения grep не совсем совпадают с регулярными выражениями sed, которые не совсем совпадают с регулярными выражениями Emacs, которые не совсем совпадают с регулярными выражениями C ++, и поэтому на. Что еще хуже, даже «стандартный» инструмент, такой как grep, может незначительно отличаться в разных Unix-подобных операционных системах.
В регулярном выражении некоторые символы имеют особое значение (например, квадратные скобки в вашем примере) и возвращаются к своему обычному значению в виде буквенных символов, когда вы «экранируете» их, помещая перед ними обратную косую черту (так что буквенная скобка будет записывается как \ [). Другие работают наоборот и приобретают особое значение только после экранирования (например, обычное n - просто буква, а \ n - перевод строки). И они, опять же, могут варьироваться между реализациями регулярных выражений.
В большинстве реализаций регулярных выражений знак вопроса означает, что предыдущий элемент является необязательным, а экранированный знак вопроса (\?) - буквальный знак вопроса. Но на нескольких диалектах все наоборот. Ваш пример может иметь смысл в любом случае, но я подозреваю, что у вас есть один из диалектов, где? это буквальное и \? это необязательный символ. Таким образом, ваше регулярное выражение, вероятно, означает «три цифры, за которыми, возможно, следует пробел или тире, за которыми следуют четыре цифры».
(В подсказках типа \ {3 \} можно увидеть другую подсказку, которая явно предназначена для обозначения «ровно 3 из предыдущего элемента». На большинстве диалектов регулярных выражений это будет написано {3}, а \ {будет литеральной скобкой .)
Это краткое изложение информации, которая уже содержится в других ответах.
In grep
, ?
соответствует буквальному символу знака вопроса и \?
обозначает ноль или одно вхождение того, что ему предшествует. Так что в примере в вашем вопросе [ -]\?
соответствует либо пробел, либо дефис, либо ничего.
В egrep
или grep -E
наоборот; \?
соответствует буквальному вопросительному знаку и ?
обозначает ноль или одно вхождение.
Это относится к GNU grep; детали реализации grep не GNU могут немного отличаться. В частности, grep
и egrep
были исторически две отдельных программы, и я не думаю , что старый grep
s имел -E
вариант. POSIX действительно указывает grep -E
, но (я был удивлен, обнаружив) не упоминает egrep
.
egrep
эквивалентнаgrep -E
. Для версий, отличных от GNU grep,grep
может принимать или не принимать эту-E
опцию иegrep
может быть отдельной программой.