Hola lector, esta entrada, tratara de amplificar una que hice, hace ya un tiempo atrás, que producto de mi parón forzado quedo en el tintero, pero que puede ser útil, tanto como recordatorio como aprendizaje para cualquiera que este interesado en entrar al scripting. Como ya debes saber la depuración o debugging, es el proceso para encontrar y corregir los errores, en el código fuente de cualquier software, tanto un simple script, como un programa, propiamente dicho. Si quiere darle un vistazo a ese post anterior, te lo dejo a continuación Manejo de errores en scripting, seria bueno que empieces por allí, si acabas de iniciarte.
Cuando recién comenzaba a hacer alguna automatización desde linea de comandos o algún desarrollo, recuerdo que pasaba muchas horas tratando de encontrar el error en mi código y, al final, podría ser algo muy simple, como una coma. Es posible que también te hayas enfrentado a la misma situación.
Saber cómo usar la técnica de depuración adecuada te ayudara a resolver los errores rápidamente. A diferencia de otros lenguajes como Python, Java, etc., no existe una herramienta de depuración para bash donde pueda establecer puntos de interrupción, pasar por alto el código, etc. Pero puedes habilitar algunas opciones en tus scripts para hacer un debugging, que pueda ayudarte, de la siguiente manera:
Habilita opciones de depuración (debugging flags) desde el shell al llamar al script:
$ bash [indicadores de depuración] scriptname
Habilita opciones de depuración pasando los indicadores de depuración a la línea shebang en el script.
#!/bin/bash [indicadores de depuración]
Habilita opciones de depuración usando el comando set del script.
set -o nounset
set -u
El comando set es un comando integrado de shell que se puede usar para controlar los parámetros de bash y alterar su comportamiento de ciertas maneras. Será ampliamente utilizado dentro de los scripts de shell, ya sea para la depuración o para habilitar el modo bash estricto. Normalmente, no ejecutarás comandos de configuración desde la terminal para modificar el comportamiento de su shell. Usa set – -help, para obtener mayor información.
Debugging
Antes de conocer las opciones de depuración, te debo comentar que puedes depurar, tanto el script completo o solo una parte determinada del código. Debe usar el comando set para habilitar y deshabilitar las opciones de depuración.
set -[flags] habilitará el modo de depuración.
set +[flags] deshabilitará el modo de depuración.
Echa un vistazo al siguiente código. set -x habilitará el modo xtrace para el script y set +x deshabilitará el modo xtrace. Todo lo que se encuentre entre set -x y set +x se ejecutará en modo de depuración xtrace.
#!/bin/bash set -x read -p "Pass Dir name : " D_OBJECT read -p "Pass File name : " F_OBJECT set +x touch ${D_OBJECT}/${F_OBJECT}
Cuando se trabaja con variables en bash, la desventaja es que si tratamos de usar una variable no definida, el script no fallará con algún mensaje de error como «Variable no definida». En su lugar, imprimirá una cadena vacía.
En el código a continuación, obtengo información del usuario y la almaceno en la variable $OBJECT. Intenté ejecutar el operador de prueba (-f y -d) en la variable $OBJECT1 que no está definida.
#!/bin/bash read -p "Nombre del Objeto : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT es un archivo" elif [[ -d $OBJECT1 ]] then echo "$OBJECT es un directorio" fi
Cuando ejecuto este código, debería haberme arrojado un error, pero no lo hizo e incluso el script salió con el código de retorno cero. Para anular este comportamiento, usa el flag -u, bash -u scriptname. generando un mensaje de error cuando se use una variable indefinida, mostrando un mensaje de error Unbound variable.
También puede configurar -u usando el comando set o pasarlo como argumento al shebang.
set -u
set -o nounset
#! /bin/bash-u
Xtrace – To the Rescue!
Este es el modo que uso cuando depuro scripts bash para errores lógicos. El modo Xtrace mostrará el código línea por línea pero con los parámetros expandidos. Ahora puedo ejecutar el mismo script anterior, en modo xtrace y ver exactamente dónde está ocurriendo el problema.
#!/bin/bash read -p "Nombre del Objeto : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT es un archivo" elif [[ -d $OBJECT1 ]] then echo "$OBJECT es un directorio" fi
Para depurar este problema, puedo ejecutar el script en modo xtrace pasando el indicador -x. bash -x scriptname. Esto me dice que hay cadenas vacías asignadas a las declaraciones condicionales -f y -d.
$ bash -x scriptname + read -p 'Nombre del Objeto : ' OBJECT Nombre del Objeto : /test/ + [[-f '']] + [[-d '']]
El signo + que ve en stdout se puede cambiar poniendo la variable PS4 en el script. De forma predeterminada, PS4 está configurado en (+), lanzando un: echo $PS4, podrás verificarlo. Para cambiarlo. lanza algo como esto:
$ PS4=" >> " bash -x scriptname
cambiando el signo +, por >>, en el stdout de tu script.
También puedes configurar el modo Xtrace usando el comando set o pasarlo como argumento al shebang.
set -x set -o xtrace
#! /bin/bash -x
No olvides, que puedes redirigir los registros de depuración a un archivo en lugar de imprimirlos en la terminal. Por ejemplo al código anterior agregue unas lineas, luego del shebang. asignano un descriptor de archivo 6 al archivo .log y BASH_XTRACEFD=»6″ redirigirá los registros de depuración de xtrace al descriptor de archivo 6.
#!/bin/bash exec 6> salida_debug.log BASH_XTRACEFD="6" ....
Cuando ejecuto este código en lugar de imprimir la salida de xtrace en la terminal, se redirigirá al archivo salida_debug.log. Usando cat, podremos leerlo dentro de la terminal.
Modo estricto de Bash
Para eliminar todos los posibles errores que hemos visto, puedes agregar algunas opciones en cada script.
- -e Salga del script si algún comando arroja un código de salida distinto de cero.
- -u Hacer que el script falle si se usa un nombre de variable indefinido.
- pipefail Si algún comando en la tubería falla, el código de salida se considerará para toda
- IFS Separador de campo interno, establecerlo en nueva línea (\ n) y (\ t) hará que la división ocurra solo en nueva línea y tabulacion.
set -e
set -u
set -o pipefail
O
set -euo pipefail
IFS=$'\n\t'
Usemos TRAP
Imagina un escenario en el que se activa el script, pero deseas cancelar lo con un CTRL+C. En ese caso, se enviará SIGINT a tu script. Con TRAP, puedes capturar esta señal y ejecutar algunos comandos o funciones.
El codigo, a continuación tiene una función llamada limpieza que se ejecutará cuando se pase SIGINT al script.
trap 'limpieza' TERM INT function limpieza(){ echo "Ejecutando limpieza, el usuario uso CTRL + C" <some logic> }
Imprima el código usando el modo Verbose
En el modo detallado (verbose), el código se imprimirá antes de devolver el resultado. Si el programa requiere una entrada interactiva, en ese caso solo se imprimirá esa línea seguida de un bloque de códigos.
Seguido a este párrafo, hay un programa simple que obtiene un objeto del usuario y verifica si object es un archivo o directorio que usa una declaración condicional.
#!/bin/bash read -p "Nombre del Objeto : " OBJECT if [[ -f $OBJECT ]] then echo "$OBJECT es un archivo" elif [[ -d $OBJECT ]] then echo "$OBJECT es un directorio" fi
Ejecutado el código anterior, primero imprimirá el código y luego esperará la entrada del usuario, hecho esto el resto del código se imprimirá seguido de la salida. $OBJECT es directorio o archivo, segun sea el caso. Como en los anteriores casos, puedes configurar el modo verbose usando set o en el shebang. set -v, set -o verbose o #! /bin/bash -v
Errores en sintaxis – modo noexec
Los errores de sintaxis son muy comunes en los programas. Es posible que haya perdido una cita o no haya podido salir del ciclo, etc. Puedes usar el flag -n (modo noexec) para validar la sintaxis antes de ejecutar el programa.
Si, se te olvido de poner una llave, una corchete, unas comillas o una coma, gracias a esta flag, podrás saberlo. mostrando mensajes de error de sintaxis. De forma predeterminada, cuando ejecutas un script, bash validará la sintaxis y arrojará estos errores incluso sin usar el modo noexec. De misma manera, como antes, puedes usar set -n, set -o noexec o #! /bin/bash -n
Conclusión
Pues buen lector, espero te sirva todos estos alcances, sobre la depuracion de scripts en bash. La gran diferencia con otros lenguajes de programación, es que no tiene herramientas de depuración aparte de algunas opciones integradas. A veces, estas opciones serán más que suficientes para realizar el trabajo y te pueden salvar de algún apuro. Hasta otro post lector, buenas vibras.
Happy Hacking!