Isso é por razões históricas.
O Regexp foi introduzido pela primeira vez no Unix na utilidade ed
no início dos anos 70. Embora ed
tenha sido baseado em qed
, cuja implementação pelos mesmos autores compreendia um regexp mais complexo, ed
entendeu apenas ^
, $
, [...]
, .
, *
e \
para escapar de todos os itens acima.
Agora, quando surgiu a necessidade de ter mais operadores, foi preciso encontrar uma maneira de apresentá-los sem quebrar a compatibilidade com versões anteriores. Se um script costumava usar o comando s
ed
como s/foo() {/foo (var) {/g
para substituir todas as instâncias de foo() {
por foo(var) {
e você introduziu um operador (
ou {
, isso quebraria esse script.
No entanto, nenhum script faria s/foo\(\) {/foo\(var\) {/
, porque isso é o mesmo que s/foo() {/foo(var) {/
e não havia razão para escapar de (
, pois esse não era um operador RE. Portanto, a introdução de um novo operador \(
ou \{
não quebra a compatibilidade com versões anteriores, já que é muito improvável que ele quebre um script existente usando a sintaxe mais antiga.
Então, foi o que foi feito. Posteriormente, \(...\)
foi adicionado inicialmente apenas para o comando s
ed
para executar ações como s/foo\(.\)/bar/
e posterior como grep '\(.\)'
(mas não como \(xx\)*
).
No UnixV7 (1979, quase uma década depois), uma nova forma de expressões regulares foi adicionada nos novos utilitários egrep
e awk
chamados de expressão regular estendida (já que são novas ferramentas, não há compatibilidade retroativa com estar quebrado). Por fim, ele forneceu a funcionalidade disponível no antigo qed
de Ken Thompson (operador de alternância |
, agrupando (..)*
) e adicionou alguns operadores como +
e ?
(mas não tinha o backref característica das expressões regulares básicas).
Mais tarde, os BSDs adicionaram \<
e \>
(ao BRE e ERE), e o SysV adicionou \{
e \}
apenas aos BREs.
Não é até muito mais tarde que {
e }
foram adicionados ao ERE, por tal quebra de compatibilidade retroativa. Nem todos adicionaram. Por exemplo, o GNU awk
até a versão 4.0.0 (2011) não suportava {
a menos que fosse forçado para o modo de conformidade POSIX.
quando o grep
do GNU foi escrito no início dos anos 90, ele adicionou todos os benefícios do BSD e SysV (como \<
, {
) e em vez de ter duas sintaxe e mecanismo de regexp separados para BRE e ERE, implementaram os mesmos operadores em ambos, apenas as contrapartes do BRE de (
, ?
, {
, +
devem ser precedidas por uma barra invertida (para ser compatível com outras implementações do BRE). É por isso que você pode fazer .\+
no GNU grep
(embora não seja POSIX ou suportado por outras implementações) e você pode fazer (.)
no GNU egrep
(embora não seja POSIX ou suportado por muitas outras implementações incluindo GNU awk
).
Adicionar \x
operadores não é a única maneira de adicionar mais operadores de maneira compatível com versões anteriores. Por exemplo, perl
usou (?...)
. Isso ainda é compatível com EREs, pois (?=...)
não é válido em EREs, mesmo para .*?
. vim
para operadores semelhantes fizeram isso de forma diferente, introduzindo \@=
ou .\{-}
, por exemplo.