Risposte:
È come ?
in molti altri motori di espressione regolare, e significa "abbina zero o uno di qualunque cosa sia venuta prima".
Nel tuo esempio, \?
viene applicato a [ -]
, il che significa che cerca di abbinare uno spazio o un segno meno, ma che lo spazio o il segno meno è facoltativo.
Quindi uno di questi corrisponderà:
555 1234
555-1234
5551234
Il motivo è scritto come \?
piuttosto che ?
per compatibilità con le versioni precedenti.
La versione originale grep
usava un diverso tipo di espressione regolare chiamata "espressione regolare di base" dove ?
significava solo un punto interrogativo letterale.
Affinché GNU grep potesse avere lo zero o una funzionalità, l'hanno aggiunta, ma ha dovuto usare la \?
sintassi in modo che gli script che utilizzavano ?
funzionassero ancora come previsto.
Si noti che grep ha -E
un'opzione che lo fa usare il tipo più comune di espressione regolare, chiamato "espressioni regolari estese".
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 \).
Ulteriori informazioni:
grep -E
è il modo POSIX ufficiale. egrep
è stato deprecato in susv2 (1997) e rimosso in susv3 (2001) dalle specifiche POSIX e Unix.
\?
è un GNUismo però.
Sfortunatamente, la sintassi esatta delle espressioni regolari varia leggermente tra i diversi programmi: le regex di grep non sono esattamente le stesse delle regex di sed, che non sono esattamente le stesse delle regex di Emacs, che non sono esattamente le stesse delle regex di C ++, e così su. A peggiorare le cose, anche uno strumento "standard" come grep può variare leggermente tra i diversi sistemi operativi simili a Unix.
In una regex, alcuni personaggi hanno un significato speciale (come le parentesi quadre nel tuo esempio), e ritornano al loro significato normale come caratteri letterali quando li "sfogli" mettendo una barra rovesciata davanti a loro (quindi una parentesi letterale sarebbe scritto come \ [). Altri lavorano al contrario e assumono un significato speciale solo quando sono fuggiti (ad esempio, il semplice n è solo una lettera, ma \ n è un avanzamento riga). E questi, ancora una volta, possono variare tra le implementazioni regex.
Nella maggior parte delle implementazioni regex, un punto interrogativo significa che l'elemento precedente è facoltativo, mentre un punto interrogativo sfuggito (\?) È un punto interrogativo letterale. Ma in alcuni dialetti è il contrario. Il tuo esempio potrebbe avere senso in entrambi i casi, ma sospetto che tu abbia uno dei dialetti dove? è un letterale e \? è il simbolo opzionale. Quindi il tuo regex probabilmente significa "tre cifre, opzionalmente seguite da uno spazio o un trattino, seguite da quattro cifre".
(Un altro indizio può essere visto in costrutti come \ {3 \}, che chiaramente intende significare "esattamente 3 dell'elemento precedente". Nella maggior parte dei dialetti regex questo sarebbe scritto {3} e \ {sarebbe una parentesi letterale .)
Questo è un breve riassunto delle informazioni che sono già contenute nelle altre risposte.
In grep
, ?
corrisponde a un carattere letterale del punto interrogativo e \?
indica zero o una ricorrenza di ciò che lo precede. Quindi, nell'esempio nella tua domanda, [ -]\?
corrisponde a uno spazio, a un trattino o niente.
In egrep
o grep -E
, è il contrario; \?
corrisponde a un punto interrogativo letterale e ?
indica zero o un'occorrenza.
Questo vale per GNU grep; i dettagli per le implementazioni grep non GNU possono differire leggermente. In particolare, grep
ed egrep
erano storicamente due programmi separati, e non credo che i vecchi grep
avessero l' -E
opzione. POSIX specifica grep -E
, ma (sono stato sorpreso di scoprire) non menziona egrep
.
egrep
comando è equivalente agrep -E
. Per versioni diverse da GNU grep,grep
potrebbe o meno accettare l'-E
opzione eegrep
potrebbe essere un programma separato.