¿Por qué C++ es el lenguaje ideal para utilidades CLI?
Cuando se trata de crear utilidades CLI en C++, muchos desarrolladores se encogen de hombros: "¿Para qué? Ya existen Python, Go, Rust". Pero seamos realistas. Si necesitas velocidad ultrarrápida, consumo mínimo de memoria y control total sobre el hardware, C++ no tiene competencia. Los administradores de sistemas, ingenieros DevOps y desarrolladores de sistemas embebidos aún escriben sus herramientas de consola en este lenguaje. ¿Y sabes qué? Es lo correcto.
Hoy analizaremos la creación de una utilidad CLI en C++ desde cero, desde el análisis de argumentos hasta la compilación del binario. Aprenderás a escribir una herramienta real y útil que no te avergüence publicar en GitHub. ¡Empecemos!
Herramientas: lo que necesitaremos
Para trabajar cómodamente necesitaremos:
- Compilador C++17/20 — GCC (MinGW en Windows) o Clang. Personalmente recomiendo GCC 11+.
- Editor de texto o IDE — VS Code con el plugin de C++, CLion, o incluso Vim (para los más hardcore).
- CMake — para una compilación sencilla. Aunque también se puede usar Makefile, CMake es el estándar moderno.
- Git — no podemos prescindir del control de versiones.
También necesitaremos una biblioteca para analizar argumentos de línea de comandos. No reinventaremos la rueda y usaremos la legendaria getopt (disponible en sistemas POSIX) o escribiremos nuestro propio analizador minimalista. La segunda opción es incluso más interesante: entenderás cómo funciona "bajo el capó".
Estructura del proyecto
Antes de escribir código, definamos qué vamos a crear. Que sea la utilidad fileutils, una herramienta de consola para trabajar con archivos. Será capaz de:
- Contar el número de líneas, palabras y caracteres en un archivo (similar a
wc). - Buscar una cadena por patrón (similar a
grepen su forma más básica). - Mostrar ayuda (
--help).
Estructura de carpetas:
fileutils/├── src/│ ├── main.cpp│ ├── parser.cpp│ └── parser.h├── CMakeLists.txt└── README.mdPaso 1: Analizador de argumentos propio
Escribamos un analizador simple pero funcional. Procesará banderas largas (--lines, --words) y argumentos posicionales (nombre del archivo).
Archivo parser.h
#ifndef PARSER_H#define PARSER_H
#include <string>#include <vector>#include <map>
struct Args { bool show_lines = false; bool show_words = false; bool show_chars = false; std::string pattern; std::vector<std::string> files;};
Args parse_args(int argc, char* argv[]);
#endifArchivo parser.cpp
#include "parser.h"#include <iostream>
Args parse_args(int argc, char* argv[]) { Args args; for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if (arg == "--help" || arg == "-h") { std::cout << "Uso: fileutils [OPCIONES] ARCHIVO..." << "Opciones:" << " --lines, -l Muestra el conteo de líneas" << " --words, -w Muestra el conteo de palabras" << " --chars, -c Muestra el conteo de caracteres" << " --search PAT Busca un patrón" << " --help, -h Muestra esta ayuda"; exit(0); } else if (arg == "--lines" || arg == "-l") { args.show_lines = true; } else if (arg == "--words" || arg == "-w") { args.show_words = true; } else if (arg == "--chars" || arg == "-c") { args.show_chars = true; } else if (arg == "--search" && i + 1 < argc) { args.pattern = argv[++i];