Cuando tu script de Bash falla: un enfoque sistemático de resolución de problemas

Depura fallos en scripts de Bash comprobando códigos de salida, rastreando comandos, aislando problemas de entorno y registrando ejecuciones desatendidas.

Cuando tu script de Bash falla: un enfoque sistemático de resolución de problemas

La resolución de problemas de fallos en scripts de Bash comienza con una pregunta: ¿falló el script porque el comando era incorrecto, el entorno era diferente o la entrada no era la esperada? Una rutina de depuración repetible evita que tengas que adivinar cuando un trabajo cron, un hook de despliegue o un script de respaldo se rompe.

Utiliza los pasos a continuación para leer la señal de fallo, rastrear lo que Bash realmente ejecutó y reducir el problema a un comando específico.


Fase 1: Preparación y evaluación inicial

Antes de sumergirte en banderas de depuración complejas, asegúrate de tener los elementos fundamentales en su lugar. Una evaluación inicial estructurada ahorra tiempo significativo.

1. Revisa el mensaje de error y el código de salida

La pista más inmediata es el mensaje de error reportado por el shell. Presta mucha atención al número de línea mencionado, si se proporciona.

  • Códigos de salida: En la programación de scripts de shell, la variable especial $? contiene el estado de salida del comando en primer plano ejecutado más recientemente. Un comando exitoso devuelve 0. Cualquier valor distinto de cero indica fallo.

    some_command
    echo "El comando salió con el estado: $?"
    # Si $? es 127, a menudo significa "comando no encontrado".
    

2. Verifica el modo de ejecución del script

Asegúrate de que el script se esté ejecutando según lo previsto, especialmente en lo que respecta al intérprete especificado por la línea shebang.

  • Shebang: Siempre comienza tu script con una línea shebang adecuada para definir el intérprete. #!/bin/bash es estándar, pero #!/usr/bin/env bash a menudo se prefiere por portabilidad.

  • Permisos: Confirma que el script tenga permisos de ejecución establecidos:

    chmod +x tu_script.sh
    

3. Aísla el entorno de ejecución

Las diferencias de entorno son una fuente importante de fallos intermitentes. Siempre prueba en el entorno donde se supone que el script debe ejecutarse, o confirma las variables que difieren entre desarrollo y producción.

  • Prueba directamente: Ejecuta el script directamente usando el intérprete, evitando posibles problemas de PATH si se ejecuta solo por nombre:

    /bin/bash ./tu_script.sh
    

Fase 2: Habilitar banderas de depuración de Bash

Bash proporciona potentes banderas integradas que pueden rastrear el flujo de ejecución y la evaluación de variables, cruciales para identificar errores de lógica o expansiones inesperadas.

1. Las banderas de depuración esenciales

Estas banderas se agregan típicamente a la línea shebang o se habilitan/deshabilitan dentro del script usando set.

Banderas Comando Propósito
-n set -n Lee comandos pero no los ejecuta (solo verificación de sintaxis).
-v set -v Imprime las líneas de entrada del shell a medida que se leen (modo verbose).
-x set -x Imprime los comandos y sus argumentos a medida que se ejecutan (modo trace). Este es el más potente para errores de lógica.

2. Usar el modo trace (set -x)

set -x antepone la salida de cada comando ejecutado con un signo +, mostrando exactamente lo que Bash está interpretando, incluyendo las expansiones de variables.

Ejemplo de rastreo:

Considera un script que falla debido a comillas incorrectas:

# Fragmento de script original
USER_INPUT="Hola Mundo"
echo $USER_INPUT  # Falla si USER_INPUT contenía espacios y se pasó a otro comando

Al ejecutar con set -x habilitado (ya sea mediante #!/bin/bash -x o set -x al inicio):

+ USER_INPUT='Hola Mundo'
+ echo Hola Mundo
Hola Mundo

Si sospechas problemas de comillas, puedes habilitar el modo trace selectivamente alrededor de la sección problemática:

set -x
# Comandos que funcionan bien

# Rastrear solo la sección problemática
COMANDO_QUE_FALLA_DEBIDO_A_EXPANSION
set +x
# Resto del script

Mejor práctica: Para depurar todo el script, usa #!/bin/bash -x o coloca set -x inmediatamente después del shebang.

3. Depurar la expansión de variables

Muchos fallos provienen de cómo se expanden (o no) las variables. Usa comillas dobles alrededor de las variables liberalmente ("$VAR") para evitar la división de palabras y la expansión de globos, pero usa el rastreo (set -x) para ver si la expansión está ocurriendo como se espera.

Si quieres ver el valor literal de una variable incluyendo espacios en blanco, puedes imprimirla envuelta en comillas y rodeada de delimitadores:

VAR="a b c"
printf '[%s]\n' "$VAR"
# Salida: [a b c]

Fase 3: Manejar tipos de error comunes

Una vez que las banderas de depuración están activas, los errores generalmente caen en categorías predecibles.

1. Comando no encontrado (Código de salida 127)

Este error, que a menudo aparece como tu_comando: comando no encontrado, indica que el shell no puede localizar el ejecutable.

  • Verifica PATH: Asegúrate de que el directorio que contiene el comando esté listado en la variable de entorno $PATH dentro del contexto de ejecución del script.
  • Usa rutas absolutas: En caso de duda, usa la ruta completa al comando (por ejemplo, /usr/bin/curl en lugar de solo curl).

2. Errores de sintaxis

Estos a menudo involucran delimitadores no coincidentes, uso incorrecto de estructuras de control (if, for, while), o falta de punto y coma/nuevas líneas.

  • set -n (Sin ejecución): Ejecutar el script con set -n obliga a Bash a analizar todo sin ejecutar, a menudo revelando corchetes no cerrados o declaraciones fi/done faltantes de inmediato.

  • Sintaxis condicional: Presta mucha atención a [[ ... ]] vs [ ... ]. Por ejemplo, probar aritmética requiere (( ... )) o let, no estructuras de prueba estándar.

    Ejemplo (Contexto aritmético):

    # Forma correcta de verificar si A es mayor que B
    A=10
    B=5
    if (( A > B )); then
        echo "A es mayor"
    fi
    

3. Permisos y problemas de entrada/salida

Si el script se ejecuta pero falla al interactuar con archivos o procesos externos, verifica los permisos y los descriptores de archivo.

  • Redirección de entrada: Si estás redirigiendo la entrada desde un archivo, asegúrate de que ese archivo exista y sea legible.

  • Redirección de salida: Verifica si el directorio de destino existe y si el usuario del script tiene permisos de escritura.

    Advertencia sobre SUDO: Si ejecutas un script con sudo, las variables de entorno como $PATH y configuraciones específicas del usuario (como .bashrc) a menudo se restablecen o cambian. Los comandos que funcionan cuando se ejecutan como usuario normal pueden fallar bajo sudo debido a la falta de contexto o rutas.

Fase 4: Registro y comprobaciones del sistema

Para scripts que se ejecutan en segundo plano (por ejemplo, mediante Cron), la salida directa del terminal no está disponible. Un registro robusto es esencial.

1. Redirigir la salida para depuración

Al ejecutar desatendido, redirige tanto la salida estándar (stdout, descriptor 1) como el error estándar (stderr, descriptor 2) a un archivo de registro. Combinarlos es común:

# Redirigir toda la salida a debug.log
./tu_script.sh >> debug.log 2>&1

Si usas set -x, la salida de rastreo irá al mismo archivo de registro, proporcionando un registro completo del flujo de ejecución y los errores.

2. Verificar la salud del sistema

A veces el script en sí está bien, pero el entorno del sistema es el problema:

  • Espacio en disco: ¿El sistema se está quedando sin espacio en disco (df -h)? Esto detendrá las operaciones de escritura.
  • Memoria: Verifica el uso de memoria (free -m). La alta presión de memoria puede hacer que los comandos externos fallen o se cuelguen.
  • Entorno de Cron: Si está programado mediante Cron, recuerda que los trabajos Cron se ejecutan con un entorno altamente restringido. Siempre define explícitamente las variables de entorno necesarias al inicio del script si no están garantizadas por la configuración del trabajo Cron.

Mantén el camino de depuración corto

Cuando tu script de Bash falla, captura primero el código de salida y el error exacto. Luego confirma el shebang, los permisos, $PATH, los archivos de entrada y el contexto del usuario. Si la causa aún no está clara, habilita set -x solo alrededor del bloque sospechoso y envía la salida desatendida a un registro.

Ese orden mantiene la resolución de problemas práctica. Pasas de la evidencia más clara al rastro más detallado sin inundarte de ruido.