Dominando el Análisis de Argumentos en Bash para Scripts Potentes
Analiza argumentos de Bash con parámetros posicionales, getopts, bucles de opciones largas, valores predeterminados y errores de uso claros.
Dominando el Análisis de Argumentos en Bash para Scripts Potentes
Los argumentos de línea de comandos son lo que hace que tus scripts de Bash sean flexibles. Cuando el análisis de argumentos de Bash es débil, terminas editando variables dentro del script cada vez que necesitas un archivo, host o modo diferente.
Esta guía te muestra cómo manejar argumentos posicionales, opciones cortas con getopts y opciones largas con un bucle while/case. El objetivo es un script que rechace entradas incorrectas temprano y te diga exactamente cómo ejecutarlo.
Lo Básico: Argumentos Posicionales
Antes de abordar banderas y opciones con nombre, es crucial entender cómo Bash maneja argumentos simples y secuenciales.
| Variable | Descripción | Ejemplo si se llama como ./script.sh foo bar |
|---|---|---|
$0 |
El nombre del script en sí | ./script.sh |
$1, $2, ... |
El primer, segundo, etc., argumento posicional | foo, bar |
$# |
El conteo de argumentos posicionales | 2 |
$@ |
Todos los argumentos posicionales, tratados como cadenas separadas | foo bar |
$* |
Todos los argumentos posicionales, tratados como una sola cadena | foo bar |
Ejemplo: Verificación Posicional Simple
#!/bin/bash
if [ "$#" -ne 2 ]; then
echo "Uso: $0 <archivo_origen> <directorio_destino>"
exit 1
fi
ORIGEN="$1"
DESTINO="$2"
echo "Copiando $ORIGEN a $DESTINO..."
# cp "$ORIGEN" "$DESTINO"
Análisis Estándar con getopts para Opciones Cortas
Para scripts profesionales que requieren opciones como -v (verbose) o -f <archivo>, la utilidad incorporada getopts es el método canónico y más confiable en Bash puro. Está diseñada específicamente para opciones cortas (de un solo carácter).
Cómo Funciona getopts
getopts lee opciones secuencialmente, estableciendo la variable designada (generalmente OPT) en la opción encontrada, y colocando el valor de cualquier argumento (si es necesario) en la variable OPTARG.
- Cadena de Opciones (OPTSTRING): Define opciones válidas. Si una opción requiere un argumento (por ejemplo,
-f nombre_archivo), sigue el carácter con dos puntos (:). Ejemplo:vho:permite-v,-h, y-oque requiere un valor. OPTIND: Un índice interno de Bash que rastrea el siguiente argumento a procesar. Debe inicializarse a 1 (que es el valor predeterminado, pero a veces se restablece en scripts complejos).
Plantilla Práctica de getopts
Esta plantilla maneja tres opciones: -v (bandera), -h (bandera) y -f (opción que requiere un valor).
#!/bin/bash
# --- Valores Predeterminados ---
VERBOSE=0
NOMBRE_ARCHIVO="predeterminado.txt"
# --- Función de Uso ---
uso() {
echo "Uso: $0 [-v] [-h] [-f <archivo>] <entrada>"
exit 1
}
# --- Bucle de Análisis de Argumentos ---
while getopts ":vhf:" OPT; do
case "$OPT" in
v)
VERBOSE=1
echo "Modo verbose habilitado."
;;
h)
uso
;;
f)
# OPTARG contiene el argumento proporcionado a -f
NOMBRE_ARCHIVO="$OPTARG"
echo "Nombre de archivo de salida establecido en: $NOMBRE_ARCHIVO"
;;
\?)
# Maneja opciones no reconocidas
echo "Error: Opción inválida -$OPTARG" >&2
uso
;;
:)
# Maneja argumentos faltantes para opciones que requieren uno (por ejemplo, -f sin un nombre de archivo)
echo "Error: La opción -$OPTARG requiere un argumento." >&2
uso
;;
esac
done
# --- Desplazamiento de Argumentos Posicionales ---
# Después de que getopts termina, OPTIND contiene el índice del primer argumento no opcional.
# Usamos shift para descartar todas las opciones analizadas, dejando solo los argumentos posicionales ($1, $2, etc.).
shift $((OPTIND - 1))
# Verificar si el argumento posicional requerido (ENTRADA) está presente
DATOS_ENTRADA="$1"
if [ -z "$DATOS_ENTRADA" ]; then
echo "Error: Se requieren datos de entrada."
uso
fi
echo "---"
echo "Procesando entrada: $DATOS_ENTRADA"
echo "Estado verbose: $VERBOSE"
Consejo: Siempre usa
shift $((OPTIND - 1))inmediatamente después del buclewhile getoptspara separar limpiamente las opciones de los argumentos posicionales restantes.
Manejo de Opciones Largas como --option
El getopts incorporado de Bash puro solo admite opciones cortas. Para manejar opciones largas modernas (por ejemplo, --verbose, --output-file=data.log), debes implementar un bucle de análisis personalizado usando while y case con el comando shift.
Este método requiere una gestión de argumentos más explícita.
Analizador de Opciones Largas Personalizado
#!/bin/bash
# --- Valores Predeterminados ---
VERBOSE=0
ARCHIVO_SALIDA=""
# Función personalizada para mostrar el uso (omitida por brevedad)
# uso() { ... }
while [ "$#" -gt 0 ]; do
case "$1" in
--verbose)
VERBOSE=1
shift
;;
--output-file)
# Requiere dos desplazamientos: uno para la bandera, uno para el valor
if [ -z "${2:-}" ]; then
echo "Error: --output-file requiere un valor."
exit 1
fi
ARCHIVO_SALIDA="$2"
shift 2
;;
--help)
uso
;;
-*)
echo "Error: Opción desconocida $1" >&2
exit 1
;;
*)
# Encontró el primer argumento posicional, detener el análisis de opciones
break
;;
esac
done
# Los argumentos restantes ahora están disponibles como $1, $2, etc.
# ... La lógica del script continúa ...
if [ "$ARCHIVO_SALIDA" ]; then
echo "Datos redirigidos a $ARCHIVO_SALIDA"
fi
Si tu script acepta argumentos posicionales después de las opciones, sigue analizando hasta que encuentres -- o el primer argumento no opcional. Una convención común es dejar que -- signifique "detener el análisis de opciones ahora":
while [ "$#" -gt 0 ]; do
case "$1" in
--)
shift
break
;;
--verbose)
VERBOSE=1
shift
;;
*)
break
;;
esac
done
Avanzado: Manejo de Opciones Largas Clave-Valor (--key=value)
Si prefieres el estilo UNIX estándar donde los argumentos se pasan usando un signo igual, necesitas usar sustitución de parámetros para dividir el argumento.
while [ "$#" -gt 0 ]; do
case "$1" in
--limit=*)
VALOR_LIMITE="${1#*=}" # Elimina todo hasta e incluyendo '='
echo "Límite establecido en: $VALOR_LIMITE"
shift
;;
# ... otras opciones ...
esac
done
Mejores Prácticas para Scripts Robusto
A. Combinando Opciones Cortas y Largas
Para máxima flexibilidad, los scripters experimentados a menudo combinan la confiabilidad de getopts para opciones cortas con el bucle while/case personalizado para opciones largas. El bucle de opciones largas se ejecuta primero, consumiendo banderas largas, y luego los argumentos restantes (incluyendo opciones cortas) son procesados por getopts.
Sin embargo, un patrón común y más limpio es procesar todos los argumentos en un bucle personalizado robusto que busque tanto -o como --option, desplazándose en consecuencia.
B. Manejo de Errores y Uso
Siempre proporciona una función uso clara que explique los argumentos y opciones requeridos del script. Esta función debe ser llamada cuando:
- El usuario solicita ayuda (por ejemplo,
-ho--help). - Falta un argumento requerido.
- Se proporciona una opción inválida o desconocida.
Asegúrate de que el script termine con un estado distinto de cero en caso de error (exit 1) y envíe mensajes de error a la Salida de Error Estándar (>&2).
C. Valores Predeterminados
Inicializa todas las variables de configuración al comienzo del script con valores predeterminados sensatos. Esto hace que tu script sea predecible incluso si no se pasan argumentos opcionales.
# Siempre inicializa las variables antes de analizar
NIVEL_LOG="info"
FORZAR=0
Conclusión
Usa argumentos posicionales para valores requeridos simples, getopts para opciones cortas portátiles y un bucle while/case personalizado cuando necesites opciones largas. Prueba valores faltantes, banderas desconocidas y argumentos con espacios antes de confiar en el script en automatización.