The following command is used to search for a 7-digit phone number:
grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file
What does \?
stand for?
It's like ?
in many other regular expression engines, and means "match zero or one of whatever came before it".
In your example, the \?
is applied to the [ -]
, meaning it tries to match a space or a minus, but that the space or minus is optional.
So any of these will match:
555 1234
555-1234
5551234
The reason it's written as \?
rather than ?
is for backwards compatibility.
The original version of grep
used a different type of regular expression called a "basic regular expression" where ?
just meant a literal question mark.
So that GNU grep could have the zero or one functionality, they added it, but had to use the \?
syntax so that scripts that used ?
still worked as expected.
Note that grep has an -E
option which makes it use the more common type of regular expression, called "extended regular expressions".
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 \).
Further info:
egrep
command is equivalent to grep -E
. For versions other than GNU grep, grep
might or might not accept the -E
option, and egrep
might be a separate program.
Commented
Nov 5, 2011 at 21:30
grep -E
is the official POSIX way. egrep
was deprecated in susv2 (1997) and removed in susv3 (2001) from the POSIX and Unix specs.
Commented
Dec 8, 2014 at 0:50
Unfortunately, the exact syntax of regular expressions varies slightly between different programs: grep regexes aren't exactly the same as sed regexes, which aren't exactly the same as Emacs regexes, which aren't exactly the same as C++ regexes, and so on. To make matters worse, even a "standard" tool like grep can vary slightly between different Unix-like operating systems.
In a regex, some characters have special meaning (such as the square brackets in your example), and revert to their normal meaning as literal characters when you "escape" them by putting a backslash in front of them (so a literal bracket would be written as \[). Others work the other way around, and only take on special meaning when escaped (e.g. plain n is just a letter, but \n is a line feed). And these, again, can vary between regex implementations.
In most regex implementations, a question mark means that the previous item is optional, while an escaped question mark (\?) is a literal question mark. But in a few dialects, it's the other way around. Your example could make sense either way around, but I suspect you have one of the dialects where ? is a literal and \? is the optional symbol. So your regex probably means "three digits, optionally followed by a space or dash, followed by four digits".
(Another clue can be seen in constructs like \{3\}, which is clearly intended to mean "exactly 3 of the previous item". In most regex dialects this would be written {3}, and \{ would be a literal brace.)
This is a quick summary of information that's already contained in the other answers.
In grep
, ?
matches a literal question-mark character, and \?
denotes zero or one occurrence of whatever precedes it. So in the example in your question, [ -]\?
matches either a space, or a hyphen, or nothing.
In egrep
or grep -E
, it's the other way around; \?
matches a literal question mark, and ?
denotes zero or one occurrence.
This applies to GNU grep; the details for non-GNU grep implementations may differ slightly. In particular, grep
and egrep
were historically two separate programs, and I don't think old grep
s had the -E
option. POSIX does specify grep -E
, but (I was surprised to discover) doesn't mention egrep
.