Respostas:
É como ?
em muitos outros mecanismos de expressão regular e significa "corresponder a zero ou a qualquer um que veio antes dele".
No seu exemplo, o \?
é aplicado a [ -]
, o que significa que ele tenta corresponder a um espaço ou menos, mas que o espaço ou menos é opcional.
Portanto, qualquer um desses itens corresponderá:
555 1234
555-1234
5551234
A razão é escrito como \?
em vez de ?
é para compatibilidade com versões anteriores.
A versão original grep
usava um tipo diferente de expressão regular chamada "expressão regular básica", onde ?
apenas significava um ponto de interrogação literal.
Para que o GNU grep pudesse ter a funcionalidade zero ou uma, eles a adicionaram, mas tiveram que usar a \?
sintaxe para que os scripts usados ?
ainda funcionassem conforme o esperado.
Observe que o grep tem uma -E
opção que o faz usar o tipo mais comum de expressão regular, chamado "expressões regulares estendidas".
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 \).
Mais informações:
grep -E
é a maneira oficial do POSIX. egrep
foi preterido em susv2 (1997) e removido em susv3 (2001) das especificações POSIX e Unix.
\?
é um GNUism embora.
Infelizmente, a sintaxe exata das expressões regulares varia um pouco entre os diferentes programas: as expressões regulares grep não são exatamente iguais às expressões sed, que não são exatamente iguais às expressões Emacs, que não são exatamente iguais às expressões C ++ e, portanto, em. Para piorar a situação, mesmo uma ferramenta "padrão" como o grep pode variar um pouco entre diferentes sistemas operacionais semelhantes ao Unix.
Em uma regex, alguns caracteres têm um significado especial (como colchetes no seu exemplo) e retornam ao seu significado normal como caracteres literais quando você "os escapa" colocando uma barra invertida na frente deles (portanto, um colchete literal seria escrito como \ [). Outros trabalham ao contrário e só assumem um significado especial quando escapam (por exemplo, n simples é apenas uma letra, mas \ n é um avanço de linha). E estes, novamente, podem variar entre implementações de regex.
Na maioria das implementações de regex, um ponto de interrogação significa que o item anterior é opcional, enquanto um ponto de interrogação com escape (\?) É um ponto de interrogação literal. Mas em alguns dialetos, é o contrário. Seu exemplo pode fazer sentido de qualquer maneira, mas suspeito que você tenha um dos dialetos onde? é um literal e \? é o símbolo opcional. Portanto, sua regex provavelmente significa "três dígitos, opcionalmente seguidos por um espaço ou traço, seguidos por quatro dígitos".
(Outra dica pode ser vista em construções como \ {3 \}, que claramente significam "exatamente 3 do item anterior". Na maioria dos dialetos regex, isso seria escrito {3} e \ {seria uma chave literal .)
Este é um resumo rápido das informações que já estão contidas nas outras respostas.
In grep
, ?
corresponde a um caractere de ponto de interrogação literal e \?
denota zero ou uma ocorrência do que o precede. Portanto, no exemplo da sua pergunta, [ -]\?
corresponde a um espaço, a um hífen ou a nada.
Em egrep
ou grep -E
, é o contrário; \?
corresponde a um ponto de interrogação literal e ?
indica zero ou uma ocorrência.
Isso se aplica ao GNU grep; os detalhes para implementações grep não-GNU podem diferir um pouco. Em particular, grep
e egrep
historicamente eram dois programas separados, e não acho que os antigos grep
tivessem a -E
opção. O POSIX especifica grep -E
, mas (fiquei surpreso ao descobrir) não menciona egrep
.
egrep
comando é equivalente agrep -E
. Para versões diferentes do GNU grep,grep
pode ou não aceitar a-E
opção eegrep
pode ser um programa separado.