¿Por qué Rust es la elección ideal para herramientas CLI?
\n\n¿Alguna vez te has preguntado por qué todas las herramientas DevOps modernas, desde bat hasta ripgrep y fd, están escritas en Rust? No es solo una cuestión de moda. Las utilidades CLI en Rust resultan increíblemente rápidas, seguras y, lo mejor de todo, se pueden compilar en un único binario diminuto sin dependencias. Nada de "¿tienes Java instalado?" o "espera a que Node.js descargue node_modules". Simplemente lo descargas y listo.
En este artículo crearemos una utilidad CLI en Rust desde cero. No será un abstracto "¡Hola, Mundo!", sino una herramienta real y útil: un analizador de logs que busca errores, cuenta su cantidad y muestra los resultados en un bonito formato a color. Y sí, lo haremos en una tarde.
\n\n¿Qué necesitamos?
\n\nPara empezar necesitamos lo mínimo:
\n- \n
- Rust (instálalo a través de
rustupsi aún no lo tienes) \n - Cualquier editor de código (VS Code con el plugin rust-analyzer es ideal) \n
- Un par de horas de tiempo libre \n
Si ya has escrito en Python o Go, Rust te parecerá inusual pero lógico. Lo principal es no tener miedo al compilador. No es malo, solo es cuidadoso.
\n\nPaso 1: Creamos el proyecto
\n\nAbrimos la terminal y escribimos:
\ncargo new log-scanner\ncd log-scanner\n\nCargo es nuestra navaja suiza. Ha creado la estructura básica con Cargo.toml (archivo de dependencias) y src/main.rs (punto de entrada). Ya puedes ejecutar cargo run y ver "Hello, world!". Pero iremos más allá.
Abrimos Cargo.toml y añadimos las dependencias que convertirán nuestro código en una auténtica utilidad CLI en Rust:
[dependencies]\nclap = { version = "4.5", features = ["derive"] }\ncolored = "2.1"\nanyhow = "1.0"\n\n- \n
- clap — análisis de argumentos de línea de comandos (imprescindible) \n
- colored — salida a color en la terminal \n
- anyhow — manejo cómodo de errores \n
Paso 2: Definimos la estructura de argumentos
\n\nLo más genial de clap son las macros derive. Simplemente describes la estructura y la magia ocurre sola. Así es como se ve:
use clap::Parser;\n\n#[derive(Parser)]\n#[command(name = "log-scanner")]\n#[command(about = "Escanea archivos de log y busca errores")]\nstruct Cli {\n /// Ruta al archivo de log\n file: String,\n\n /// Cadena a buscar (por defecto "ERROR")\n #[arg(short, long, default_value = "ERROR")]\n pattern: String,\n\n /// Mostrar solo la cantidad de líneas encontradas\n #[arg(short, long)]\n count: bool,\n}\n\nObserva: los comentarios con tres barras /// se convierten automáticamente en sugerencias en --help. Ejecuta cargo run -- --help y verás una ayuda generada ordenadamente. Esta es una de las razones por las que crear CLI en Rust es tan agradable: la documentación se escribe sola.
Paso 3: Escribimos la lógica de búsqueda
\n\nAhora viene lo interesante: leer el archivo y buscar coincidencias. Rust es famoso por su trabajo seguro con archivos y memoria, pero en la práctica es simplemente cómodo:
\n\nuse std::fs::File;\nuse std::io::{BufRead, BufReader};\nuse colored::*;\nuse anyhow::Result;\n\nfn scan_log(file_path: &str, pattern: &str, count_only: bool) -> Result<()> {\n let file = File::open(file_path)?;\n let reader = BufReader::new(file);\n let mut total_matches = 0;\n\n for (line_num, line) in reader.lines().enumerate() {\n let line = line?;\n if line.contains(pattern) {\n total_matches += 1;\n if !count_only {\n println!(\n "{}:{} {}",\n format!("{:>4}", line_num + 1).blue(),\n patt