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.