Cómo leer los argumentos en C, lo que se escribe detrás del nombre del programa: argc y argv, opciones cortas y largas con getopt_long, valores numéricos comprobados, una ayuda con --help y los códigos de salida que esperan los scripts.
También te puede interesar
argc y argv
Lo que se escribe detrás del nombre del programa llega a main en dos parámetros: argc, cuántos argumentos hay, y argv, un array de cadenas con cada uno. argv[0] es el nombre con el que se ejecutó el programa y el array termina con un puntero nulo:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("argc = %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("argv[%d] = [%s]\n", i, argv[i]);
}
printf("argv[argc] es %s\n", argv[argc] == nullptr ? "nulo" : "otra cosa");
return 0;
}./argv hola "dos palabras" -x
salidaargc = 4 argv[0] = [./argv] argv[1] = [hola] argv[2] = [dos palabras] argv[3] = [-x] argv[argc] es nulo
Es el intérprete de órdenes, no el programa, quien separa los argumentos por los espacios y quita las comillas: «dos palabras» llega como un solo argumento. argv[0] es tal como se escribió la orden, ./argv, y por eso los mensajes de error suelen usarlo como nombre del programa.
Opciones con getopt_long
Analizar a mano opciones como -n 5, --lineas=5 o -vn5 es tedioso y fácil de hacer mal. getopt (de POSIX) hace las opciones cortas, y getopt_long (de GNU, también en macOS y los BSD) añade las largas con --:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
static void ayuda(const char *programa)
{
printf("Uso: %s [opciones] archivo...\n"
" -n, --lineas N cuántas líneas mostrar (por omisión, 10)\n"
" -v, --detalle explicar lo que hace\n"
" -h, --help mostrar esta ayuda\n", programa);
}
int main(int argc, char *argv[])
{
long lineas = 10;
bool detalle = false;
static const struct option largas[] = {
{"lineas", required_argument, nullptr, 'n'},
{"detalle", no_argument, nullptr, 'v'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0},
};
int op;
while ((op = getopt_long(argc, argv, "n:vh", largas, nullptr)) != -1) {
switch (op) {
case 'n': {
char *fin;
lineas = strtol(optarg, &fin, 10);
if (*fin != '\0' || lineas <= 0) {
fprintf(stderr, "%s: -n necesita un número positivo, no «%s»\n", argv[0], optarg);
return 2;
}
break;
}
case 'v':
detalle = true;
break;
case 'h':
ayuda(argv[0]);
return 0;
default:
ayuda(argv[0]);
return 2;
}
}
if (optind == argc) {
fprintf(stderr, "%s: falta al menos un archivo\n", argv[0]);
return 2;
}
for (int i = optind; i < argc; i++) {
if (detalle) printf("Mostraría %ld líneas de ", lineas);
printf("%s\n", argv[i]);
}
return 0;
}Cómo responde a distintas órdenes:
./opciones -v --lineas 5 informe.txt datos.csv
salidaMostraría 5 líneas de informe.txt Mostraría 5 líneas de datos.csv
./opciones -n diez informe.txt; echo $?
salida con error./opciones: -n necesita un número positivo, no «diez» 2
./opciones --color informe.txt; echo $?
salida con error./opciones: unrecognized option '--color' Uso: ./opciones [opciones] archivo... -n, --lineas N cuántas líneas mostrar (por omisión, 10) -v, --detalle explicar lo que hace -h, --help mostrar esta ayuda 2
./opciones -v; echo $?
salida con error./opciones: falta al menos un archivo 2
Lo más importante del ejemplo:
- La cadena
"n:vh"declara las opciones cortas; los dos puntos tras landicen que lleva un valor, que llega enoptarg. El arraylargasasocia cada opción larga con su letra y termina con una fila de ceros. - Al acabar,
optindes el índice del primer argumento que no es una opción: lo que queda son los archivos. GNUgetoptreordenaargvpara que las opciones puedan ir antes o después de los archivos, y--marca el final de las opciones (para un archivo que empiece por guion). - El valor de
-nse convierte constrtolcomprobando que no sobre nada:atoi("diez")devolvería 0 sin avisar. - Los códigos de salida siguen la costumbre de Unix: 0 si todo fue bien, y 2 para un uso incorrecto, como hacen
grepols. Los errores van astderr, y--help, que no es un error, astdoutcon código 0.
- En la cadena de opcionesSignifica
vopción sin valor:-vn:opción con valor obligatorio:-n 5o-n5c::valor opcional (extensión de GNU), solo pegado:-c5:al principiogetoptno escribe sus propios mensajes de error
Todo el código de esta página se compiló con GCC 15.3 (C23, -Wall -Wextra, sin avisos) y se ejecutó en Linux, en un contenedor limpio sin acceso a la red, antes de publicarla; las salidas están copiadas de esa ejecución.