Las herramientas CLI escritas en Rust como ripgrep, fd y bat son más rápidas que sus equivalentes clásicos de UNIX por cuatro razones concretas: escaneo de bytes acelerado por SIMD (el algoritmo Teddy), abstracciones sin coste que compilan código de alto nivel a instrucciones máquina al nivel de C, paralelismo con robo de trabajo mediante Rayon que satura todos los núcleos de la CPU, y respeto automático por .gitignore, que evita leer archivos que nunca quisiste buscar. Sobre el árbol de fuentes del kernel Linux, ripgrep corre unas 9 veces más rápido que GNU grep; en un repositorio típico de Node.js con node_modules en disco, la diferencia puede superar las 300 veces.
Seguro que ya lo notaste. Ejecutaste rg TODO en un monorepo y el resultado apareció antes de que retiraras los dedos del teclado. Luego por costumbre probaste grep -r TODO ., fuiste por un café, y al volver seguía arrastrándose. La pregunta que trae a la gente hasta este artículo es la misma: ¿por qué la versión en Rust es tanto más rápida? ¿Y realmente es siempre más rápida?
La respuesta corta es "sí, casi siempre", pero lo interesante es por qué, porque las razones no son magia. Rust no reinventó la búsqueda de texto ni el recorrido del sistema de archivos. Combinó cuatro decisiones de ingeniería concretas que coreutils clásico necesitaría reescribir desde cero para igualar. Y esa reescritura está ocurriendo: el proyecto uutils/coreutils entró como implementación por defecto en Ubuntu 25.10 y continúa en Ubuntu 26.04 LTS.
Si lo que buscas es la guía práctica de instalación y alias para tu shell, empieza por el resumen de herramientas CLI modernas en Rust. Este artículo es el por qué detrás de la velocidad.
Las cuatro razones reales por las que Rust supera a sus predecesores
Antes de entrar en materia conviene aclarar lo que no vamos a decir. Rust no es más rápido que C. Un programa en C que use los mismos algoritmos y los mismos intrínsecos SIMD sería igual de rápido — y GNU grep ha sido históricamente un pedazo de código C extraordinariamente bien afinado. La razón por la que ripgrep le gana a GNU grep no es que Rust sea un lenguaje mágicamente veloz. Es que los autores de ripgrep implementaron un conjunto mejor de algoritmos, y Rust hizo que escribir esos algoritmos de forma segura fuera fácil.
Estas son las cuatro razones, cada una con su propia sección más abajo.
- Escaneo de bytes con SIMD mediante el algoritmo Teddy y
memchr: 16 a 32 bytes por ciclo en lugar de uno. - Abstracciones sin coste — iteradores, genéricos y código de alto nivel compilan al mismo código máquina que escribirías a mano en C. Sin recolector de basura, sin coste en tiempo de ejecución.
- Paralelismo con robo de trabajo vía Rayon — recorridos del sistema de archivos y búsquedas se distribuyen por todos los núcleos de CPU con unas pocas líneas de código. Algo que los coreutils clásicos casi nunca hacen.
- Respeto por
.gitignore— los repositorios reales contienen cantidades enormes de basura generada (node_modules,target,dist,.venv). Saltarlos no es una optimización, es una corrección.
Sobre el árbol de fuentes del kernel Linux, un benchmark reciente mostró ripgrep corriendo unas 9.2 veces más rápido que GNU grep al buscar EXPORT_SYMBOL, y unas 11.8 veces más rápido con una expresión regular como spin_lock.*irq. En un proyecto Node.js con node_modules presente, ripgrep termina unas 302 veces más rápido que grep con los flags por defecto — y sigue siendo 21 veces más rápido incluso cuando a grep se le dice manualmente que excluya node_modules.
SIMD y el algoritmo Teddy: escanear 16 bytes a la vez
La razón técnica más importante detrás de la velocidad de las CLIs en Rust es SIMD (Single Instruction, Multiple Data). Los CPUs modernos x86-64 y ARM tienen registros vectoriales de 128 o 256 bits, lo que significa que una sola instrucción puede comparar 16 o 32 bytes a la vez. Los bucles tradicionales en C que procesan un byte por iteración sólo tocan un carácter por ciclo. El código SIMD toca dieciséis. Esa es la diferencia.
El crate regex de Rust — el mismo motor de expresiones regulares que usa ripgrep — se apoya fuertemente en un algoritmo SIMD llamado Teddy, originalmente desarrollado por Geoffrey Langdale como parte de la biblioteca de regex Hyperscan de Intel. Teddy no es un motor de regex de propósito general. Es un prefiltro especializado que encuentra posiciones candidatas en un texto donde un conjunto de cadenas literales podría coincidir, usando comparaciones de bytes empaquetados. Sólo cuando aparece un candidato entra en acción el motor completo, que es mucho más lento.
En la práctica, esto significa que ripgrep escanea la mayor parte del archivo a una velocidad cercana al ancho de banda de memoria, deteniéndose a "pensar" sólo cuando encuentra algo sospechoso. El análisis técnico profundo está en el desglose de rendimiento de ripgrep escrito por BurntSushi.
Además de Teddy, ripgrep usa el crate memchr, una primitiva de búsqueda de bytes acelerada por SIMD que examina 16 bytes por iteración. El conteo de líneas — uno de los costes ocultos de cualquier grep — usa comparaciones empaquetadas para contar saltos de línea de 16 en 16 en vez de uno por uno.
# Sobre un clon del kernel Linux, comparación real
hyperfine --warmup 2 \
'grep -r "EXPORT_SYMBOL" linux/' \
'rg "EXPORT_SYMBOL" linux/'
Si instalas hyperfine (también escrito en Rust) y ejecutas el comando de arriba, el ratio que verás variará según tu CPU y almacenamiento, pero ripgrep se mantendrá consistentemente en el rango de 5x–15x dependiendo del escenario.
¿Por qué GNU grep no hace esto simplemente?
Lo han intentado. GNU grep usa algo de SIMD en casos específicos y es sorprendentemente rápido sobre archivos ASCII sueltos. Pero arrastra décadas de compatibilidad con POSIX, soporta locales antiguos y codificaciones de caracteres legacy, y tiene una base instalada enorme. Una reescritura al estilo Teddy es un riesgo demasiado grande. ripgrep tuvo el lujo de empezar de cero en 2016 apuntando a flujos de trabajo modernos de desarrollo: Unicode por defecto, UTF-8 por defecto, .gitignore por defecto.
Abstracciones de coste cero: seguridad sin perder velocidad
Esta es la parte que hace tropezar a la gente. Rust tiene iteradores, closures, traits, genéricos, Option, Result y todas las construcciones de alto nivel que encontrarías en un lenguaje de scripting. Y sin embargo la salida compilada corre a velocidad de C. ¿Cómo?
La respuesta es monomorfización más optimización de LLVM. Cuando escribes una función genérica en Rust, el compilador genera una copia especializada por cada tipo concreto en tiempo de compilación. No hay despacho dinámico, no hay lookup de vtable, no hay borrado de tipos. Para cuando se produce el código máquina, la "abstracción" se ha evaporado. Lo que queda es exactamente el código que habrías escrito a mano.
Concretamente, para una herramienta CLI esto significa:
iter().filter().map().collect()compila al mismo bucle que escribirías en C a mano.Option<T>yResult<T, E>tienen coste cero en tiempo de ejecución — se representan como uniones etiquetadas y se integran inline.Box<T>yRc<T>sólo asignan memoria cuando los usas de verdad; no hay runtime escondido.- No hay pausas del recolector de basura. La memoria se libera en el instante en que la variable propietaria sale del ámbito.
Compara esto con herramientas escritas en Python, Ruby o Node.js. Cada llamada a función cruza un límite de la VM, cada objeto vive detrás de una capa de indirección, y el GC puede pausar durante decenas de milisegundos en momentos impredecibles. Esa es la razón por la que herramientas escritas en lenguajes de scripting — incluso buenas como ack (Perl) o ag (C, pero limitado por I/O) — no pueden seguirle el ritmo a las CLIs en Rust sobre corpus grandes.
Rayon y concurrencia sin miedo: recorridos paralelos del sistema de archivos
La tercera razón es la más fácil de explicar y probablemente la de mayor impacto para herramientas de recorrido de directorios como fd y la búsqueda recursiva de ripgrep.
Rayon es una biblioteca Rust que permite convertir cualquier iterador secuencial en uno paralelo cambiando .iter() por .par_iter(). Bajo el capó usa un pool de hilos con robo de trabajo: los hilos ociosos roban tareas a los ocupados, manteniendo cada núcleo saturado sin que tengas que escribir una sola línea de código de locking.
El sistema de propiedad de Rust garantiza en tiempo de compilación que tu código paralelo no tiene carreras de datos. El término "fearless concurrency" (concurrencia sin miedo) no es marketing — el borrow checker literalmente se niega a compilar código que corrompería estado compartido. Para una CLI que quiere recorrer millones de archivos en 16 núcleos, esto convierte un problema de threading que te hace perder el pelo en un cambio de una línea.
fd, el reemplazo de find en Rust, usa esto para paralelizar el recorrido de directorios. En benchmarks reales sobre árboles grandes, fd es típicamente 5x–9x más rápido que find -iname y 9x–23x más rápido que find -iregex, dependiendo del sistema de archivos y del patrón. El recorrido subyacente lo manejan walkdir (secuencial) o el crate ignore (paralelo y con soporte para gitignore), ambos mantenidos por el autor de ripgrep.
# fd vs find, comparación real
hyperfine --warmup 2 \
'find /usr -iname "*.so"' \
'fd -e so . /usr'
Respeto por .gitignore: la ventaja injusta en repos reales
Esta es la razón por la que los benchmarks casuales muestran ripgrep "300 veces más rápido" mientras que los benchmarks serios muestran "9 veces más rápido". Las dos cifras son correctas; sólo miden cosas distintas.
La verdad es que los repositorios reales contienen cantidades alucinantes de contenido generado por máquina. Un npm install fresco suelta 200 MB de JavaScript en node_modules. Un proyecto Rust compila cientos de megabytes de .rlib y .o bajo target/. Un virtualenv de Python esconde una instalación completa de Python bajo .venv/. El clásico grep -r busca diligentemente sobre todo eso. Tú no querías eso. Nunca lo quisiste.
ripgrep y fd leen automáticamente tus archivos .gitignore, .ignore y .rgignore y saltan lo que coincida. El resultado es que no sólo escanean más rápido, sino que escanean muchos menos datos. En un monorepo Node.js típico, grep -r puede tocar 2 GB de archivos mientras rg toca 80 MB. Incluso si ambas herramientas tuvieran velocidad de escaneo idéntica, ripgrep ganaría por un orden de magnitud sólo leyendo menos.
Por eso el benchmark de "302x" en repos con muchos node_modules se siente casi injusto. No es una comparación algorítmica pura, es una comparación entre "buscar en todo" y "buscar en lo que un desarrollador realmente quiere buscar". Para el trabajo diario, la cifra con .gitignore activado es la honesta, porque refleja lo que experimentas de verdad.
Si de verdad necesitas buscar archivos que .gitignore normalmente excluiría, pasa rg --no-ignore o rg -uuu (tres niveles de "sin restricciones") — el comportamiento por defecto es opinado, no está bloqueado. Puedes leer más sobre las decisiones de diseño de .gitignore en ripgrep en el FAQ del proyecto. La idea clave de Andrew Gallant, autor de ripgrep, es que las herramientas de desarrollo deberían venir por defecto alineadas con las expectativas del desarrollador.
uutils y Ubuntu 26.04: Rust se convierte en el nuevo estándar
La historia hasta aquí trata de herramientas nuevas que se sitúan junto a grep, find y cat. Pero en paralelo hay otra historia: Rust está reemplazando silenciosamente a las clásicas directamente.
El proyecto uutils/coreutils es una reimplementación en Rust de GNU coreutils: ls, cp, mv, cat, date, rm y alrededor de 100 comandos fundamentales más. En noviembre de 2025, Ubuntu 25.10 puso uutils como implementación por defecto de coreutils, una primicia para cualquier distribución Linux importante. Ubuntu 26.04 LTS "Resolute Raccoon" continúa esa elección y será la primera versión de soporte extendido (LTS) en venir con Rust coreutils por defecto cuando salga el 23 de abril de 2026.
En la versión actual (uutils 0.8.0), el proyecto pasa aproximadamente el 88% de los tests de compatibilidad con GNU coreutils. Para el usuario final, la transición es invisible — los comandos funcionan igual, las flags se comportan igual, la salida se ve igual. Las motivaciones detrás del cambio no son principalmente rendimiento (GNU coreutils ya es C extremadamente rápido), sino seguridad de memoria: categorías enteras de bugs de buffer overflow, use-after-free y overflow de enteros son imposibles de escribir en Rust seguro.
Sylvestre Ledru, el mantenedor principal de uutils, presentó el estado actual del proyecto en la FOSDEM 2026, incluyendo cifras honestas sobre dónde Rust coreutils es aún más lento que GNU (algunas herramientas especializadas como sort y cp siguen por detrás en ciertas cargas de trabajo) y dónde ya es más rápido o igual.
Si estás en Ubuntu 25.10 o posterior, prueba esto:
# Comprobar qué implementación de coreutils tienes
which ls
ls --version | head -n 1
En uutils, ls --version muestra ls (uutils coreutils) 0.8.0 (o la versión que traiga tu distribución). En GNU, muestra ls (GNU coreutils) 9.x. Cualquiera de las dos funciona — a tus scripts de shell les da igual.
FAQ
¿Rust es realmente más rápido que C para herramientas CLI?
No, y esa es la pregunta equivocada. Un programa en C bien escrito usando los mismos algoritmos será tan rápido como la versión en Rust. La razón por la que las CLIs en Rust ganan a las CLIs en C es que las versiones en Rust se escribieron recientemente con algoritmos modernos (SIMD, paralelismo con robo de trabajo, .gitignore), mientras que las versiones en C se escribieron hace décadas y arrastran compatibilidad. La verdadera contribución de Rust es hacer que esos algoritmos modernos sean más fáciles de escribir de forma segura.
¿Por qué no reescribir simplemente GNU grep con SIMD?
Lo han intentado. GNU grep usa algo de SIMD en casos específicos, pero sus requisitos de cumplimiento POSIX, su soporte para locales antiguos y codificaciones de caracteres legacy, y su enorme base instalada hacen que una reescritura total al estilo Teddy sea extremadamente arriesgada. ripgrep tuvo la libertad de romper la compatibilidad a cambio de un diseño más limpio enfocado en los flujos modernos de desarrollo.
¿El salto automático de .gitignore causa problemas alguna vez?
Sí. Si necesitas encontrar un archivo que tu .gitignore excluye — por ejemplo, un secreto accidentalmente commiteado dentro de node_modules — tienes que pasar explícitamente --no-ignore (o -uuu para la opción nuclear). El salto silencioso es opinado y ocasionalmente sorprendente. Es un trade-off real, y algunos flujos de administración de sistemas prefieren el comportamiento directo del find y grep clásicos precisamente por esto.
¿Debería reemplazar grep y find en todos mis scripts de shell?
No. Usa grep, find y cat compatibles con POSIX en los scripts que tienen que correr en cualquier máquina. Usa ripgrep, fd y bat para el trabajo interactivo en la línea de comandos. Esta es la misma distinción que recomendamos en el resumen de herramientas CLI modernas en Rust. La portabilidad importa más que la velocidad cuando tu script tiene que correr en CI sobre una imagen de contenedor mínima.
¿Ubuntu 26.04 va a romper mis scripts?
Casi seguro que no. uutils apunta al 100% de compatibilidad con GNU y actualmente alcanza aproximadamente el 88%. La mayoría de los scripts del mundo real nunca tocan los casos límite donde uutils y GNU divergen. Si te topas con una regresión, puedes instalar GNU coreutils desde un paquete de fallback. Las incompatibilidades conocidas se rastrean en los issues de GitHub.
¿Hay algún benchmark que pueda correr yo mismo?
Sí. Instala hyperfine y prueba esto sobre cualquier codebase grande que tengas localmente:
hyperfine --warmup 3 \
'grep -r "TODO" /path/to/repo' \
'rg "TODO" /path/to/repo'
Los runs de calentamiento son críticos — la primera ejecución normalmente lee de caché fría y sesga los resultados. Incluye siempre al menos 2 o 3 iteraciones de warmup cuando hagas benchmarks de CLIs basadas en archivos.
¿Y ripgrep-all (rga)?
ripgrep-all envuelve ripgrep para buscar también dentro de PDFs, ebooks, documentos de Office y bases de datos SQLite. Es un producto distinto con un perfil de rendimiento diferente — el cuello de botella pasa a ser el parser de documentos, no el motor de regex. Útil, pero no la herramienta que buscas cuando quieres buscar código fuente plano.
Conclusión
El meme "Rust es rápido" oculta la verdadera historia de ingeniería. Las CLIs en Rust son rápidas porque sus autores eligieron algoritmos acelerados por SIMD, porque el lenguaje hace fácil escribir paralelismo y abstracciones sin coste de forma segura, y porque se atrevieron a romper con la tradición POSIX en decisiones por defecto como el manejo de .gitignore. Una reescritura en C con las mismas decisiones de diseño sería comparablemente rápida — pero nadie la ha hecho, y la energía está en Rust.
Para el desarrollo diario, la conclusión práctica es simple: usa ripgrep, fd y bat para el trabajo interactivo, mantén grep y find en tus scripts de shell, y observa el proyecto uutils durante los próximos años mientras avanza hacia la compatibilidad total con GNU. Para cuando salga Ubuntu 28.04, la línea entre "coreutils clásicos" y "coreutils de Rust" probablemente se habrá difuminado hasta el punto en que nadie se dará cuenta de cuál está instalado.
Si quieres instalar y configurar estas herramientas en la práctica, la guía de CLIs modernas en Rust cubre instalación, alias e integración con fzf y tu shell. Para la migración específica de grep a ripgrep, el análisis profundo de grep y ripgrep recorre flag por flag todo lo que necesitas. Y si todavía estás intentando descifrar qué CLI moderna resuelve qué problema, el mapa de herramientas CLI es el mejor punto de partida.
La versión corta: Rust no rompió las leyes de la física. Sólo abarató el coste de escribir el código que deberíamos haber estado escribiendo todo este tiempo.