Cuando grepo sedse usan con la opción --extended-regexpy el patrón {1,9999}es una parte de la expresión regular que se usa, el rendimiento de estos comandos se vuelve bajo. Para ser más claro, a continuación se aplican algunas pruebas. [1] [2]
- El rendimiento relativo de
grep -E,egrepysed -Ees casi igual, por lo que solo se proporcionan las pruebas realizadasgrep -E.
Prueba 1
$ time grep -E '[0-9]{1,99}' < /dev/null
real 0m0.002s
Prueba 2
$ time grep -E '[0-9]{1,9999}' < /dev/null
> real 0m0.494s
Prueba 3
$ time grep -E '[0123456789] {1,9999}' </ dev / null
> real 21m43.947s
Prueba 4
$ time grep -E '[0123456789]+' < /dev/null
$ time grep -E '[0123456789]*' < /dev/null
$ time grep -E '[0123456789]{1,}' < /dev/null
$ time grep -P '[0123456789]{1,9999}' < /dev/null
real 0m0.002s
¿Cuál es la razón de esta diferencia significativa de rendimiento?
command-line
grep
regex
pa4080
fuente
fuente

[0-9]+también)time grep -E '[0-9]{1,99}' </dev/nullvstime grep -E '[0-9]{1,9999}' </dev/null. Incluso sin entrada , el segundo comando es lento (en 16.04). Como se esperaba, omitir-Ey escapar{y se}comporta igual y reemplazar-Econ-Pno es lento (PCRE es un motor diferente). Lo más interesante es cuánto más rápido[0-9]es que.,xy hasta[0123456789]. Con cualquiera de esos y{1,9999},grepconsume una gran cantidad de RAM; No me he atrevido a dejarlo correr por más de ~ 10 minutos.{}se''citan ; el caparazón los pasa sin cambiosgrep. De todos modos,{1,9999}sería una expansión de llaves muy rápida y simple . El shell simplemente lo expandiría a1 9999.psytoppara verificargrepse pasaron los argumentos esperados y que, nobash, consume mucha RAM y CPU. Esperogrepysedambos usan las funciones de expresiones regulares POSIX implementadas en libc para la coincidencia BRE / ERE; Realmente no debería haber habladogrepespecíficamente del diseño, excepto en la medida en que losgrepdesarrolladores eligieron usar esa biblioteca.time grep ... < /dev/null, para que las personas no combinen el problema real con los datos que se envíangrepy otras cosas extrañas.Respuestas:
Tenga en cuenta que no es la correspondencia lo que lleva tiempo, sino la construcción del RE. Encontrarás que también usa bastante RAM:
El número de asignaciones parece aproximadamente proporcional al número de iteraciones, pero la memoria asignada parece crecer exponencialmente.
Eso se debe a cómo se implementan las expresiones regulares GNU. Si compila GNU
grepconCPPFLAGS=-DDEBUG ./configure && makey ejecuta esos comandos, verá el efecto exponencial en acción. Ir más profundo que eso significaría pasar por muchas teorías sobre DFA y sumergirse en la implementación de expresiones regulares de gnulib.Aquí, puede usar PCRE en su lugar que no parece tener el mismo problema:
grep -Po '[0-9]{1,65535}'(el máximo, aunque siempre puede hacer cosas como[0-9](?:[0-9]{0,10000}){100}1 a 1,000,001 repeticiones) no toma más tiempo ni memoria quegrep -Po '[0-9]{1,2}'.fuente
grep -Po '[0-9]{1,9999}lo que no parece tener el problema.sed -Eogrep -E, pero en laawkque también tiene este bajo rendimiento (alrededor del último comando awk). tal vezawktampoco puede usar PCRE?