以下命令用于搜索 7 位数字的电话号码:
grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file
\?
代表什么?
答案1
它就像?
许多其他正则表达式引擎一样,意味着“匹配零个或之前的任何一个”。
在您的示例中,\?
应用于[ -]
,这意味着它尝试匹配空格或减号,但空格或减号是可选的。
因此,其中任何一个都会匹配:
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
选项和egrep
- GNU grep - 基本与扩展
- 正则表达式语法摘要
- 正则表达式 - 维基百科
- 为什么某些正则表达式命令对不同字符的“\”有相反的解释?
答案2
不幸的是,不同程序之间正则表达式的确切语法略有不同:grep 正则表达式与 sed 正则表达式不完全相同,后者与 Emacs 正则表达式不完全相同,而 Emacs 正则表达式又与 C++ 正则表达式不完全相同,等等在。更糟糕的是,即使是像 grep 这样的“标准”工具,在不同的类 Unix 操作系统之间也会略有不同。
在正则表达式中,某些字符具有特殊含义(例如示例中的方括号),当您通过在它们前面放置反斜杠来“转义”它们时,它们将恢复为文字字符的正常含义(因此文字括号将是写为\[)。其他的则相反,只有在转义时才具有特殊含义(例如,普通的 n 只是一个字母,但 \n 是换行符)。同样,这些在正则表达式实现之间可能有所不同。
在大多数正则表达式实现中,问号意味着前一项是可选的,而转义问号 (\?) 是字面问号。但在某些方言中,情况恰恰相反。你的例子无论哪种方式都有意义,但我怀疑你有一种方言在哪里?是一个文字并且 \?是可选符号。因此,您的正则表达式可能意味着“三位数字,可选地后跟空格或破折号,后跟四位数字”。
(另一个线索可以在像 \{3\} 这样的结构中看到,它显然意味着“恰好是前一项的 3 个”。在大多数正则表达式方言中,这将被写成 {3},而 \{ 将是一个文字大括号.)
答案3
这是其他答案中已包含的信息的快速摘要。
在 中grep
,?
匹配字面上的问号字符,并\?
表示其前面的任何内容出现零次或一次。因此,在您问题的示例中,[ -]\?
匹配空格或连字符,或不匹配任何内容。
在egrep
or中grep -E
,情况正好相反;\?
匹配字面问号,?
表示出现零次或一次。
这适用于 GNU grep;非 GNU grep 实现的细节可能略有不同。特别是,grep
和egrep
历史上是两个独立的程序,我认为旧grep
的没有-E
选择。 POSIX 确实指定了grep -E
,但是(我惊讶地发现)没有提及egrep
。