Eso es por razones históricas.
Regexp se introdujo por primera vez en Unix en la ed
utilidad a principios de los años 70. Aunque ed
se basa en qed
cuya aplicación por parte de los mismos autores entendieron expresión regular más complejo, ed
sólo se entiende ^
, $
, [...]
, .
, *
y \
para escapar de todo lo anterior.
Ahora, cuando surgió la necesidad de tener más operadores, se tuvo que encontrar una manera de introducirlos sin romper la compatibilidad con versiones anteriores. Si un script solía usar el s
ed
comando s/foo() {/foo (var) {/g
para reemplazar todas las instancias de foo() {
con foo(var) {
y usted introdujo un operador (
u {
, eso rompería ese script.
Sin embargo, ningún script funcionaría s/foo\(\) {/foo\(var\) {/
, porque es lo mismo s/foo() {/foo(var) {/
y no había razón para escapar (
ya que no era un operador RE. Por lo tanto, la introducción de un operador nuevo \(
o \{
no rompe la compatibilidad con versiones anteriores, ya que es muy poco probable que rompa un script existente utilizando la sintaxis anterior.
Entonces, eso fue lo que se hizo. Más tarde, \(...\)
se agregó inicialmente solo para que el s
ed
comando haga cosas como s/foo\(.\)/\1bar/
y luego como grep '\(.\)\1'
(pero aún no cosas como \(xx\)*
).
En UnixV7 (1979, casi una década después), se agregó una nueva forma de expresiones regulares en las nuevas egrep
y las awk
utilidades llamadas expresiones regulares extendidas (dado que son nuevas herramientas, no hay compatibilidad con versiones anteriores que se rompan). Finalmente, proporcionó la funcionalidad disponible en el antiguo Ken Thompson qed
(operador de alternancia |
, agrupación (..)*
) y agregó algunos operadores como +
y ?
(pero no tenía la función de reflujo de las expresiones regulares básicas).
Más tarde, se agregaron BSD \<
y \>
(tanto a BRE como a ERE), y SysV se agregó \{
y \}
solo a BRE.
No es hasta mucho más tarde {
y }
se agregaron a ERE, al romper la compatibilidad con versiones anteriores. No todos lo agregaron. Por ejemplo, GNU awk
hasta la versión 4.0.0 (2011) no era compatible a {
menos que fuera forzado al modo de conformidad POSIX.
cuando GNU grep
se escribió a principios de los 90, agregó todas las ventajas de BSD y SysV (como \<
, {
) , y en lugar de tener dos sintaxis regexp y un motor separados para BRE y ERE, implementó los mismos operadores en ambos, solo los equivalentes BRE de (
, ?
, {
, +
tiene que ser precedido por una barra invertida (para que sea compatible con otras implementaciones BRE). Es por eso que puede hacerlo .\+
en GNU grep
(aunque eso no es POSIX o no es compatible con otras implementaciones) y puede hacerlo (.)\1
en GNU egrep
(aunque eso no es POSIX ni es compatible con muchas otras implementaciones, incluida GNU awk
).
Agregar \x
operadores no es la única forma de agregar más operadores de una manera compatible con versiones anteriores. Por ejemplo, perl
usado (?...)
. Eso sigue siendo compatible con versiones anteriores de ERE, ya (?=...)
que no es válido en ERE, lo mismo para .*?
. vim
para operadores similares lo hizo de manera diferente introduciendo \@=
o .\{-}
por ejemplo.