jueves, 15 de noviembre de 2018

bash en modo debug

Bash permite la ejecución de shell scripts bastante potentes. A menudo, este es un recurso muy utilizado por administradores de sistemas para labores de lo más variadas.
A todo el mundo el ocurre en alguna ocasión que un script no hace lo que debería, falla en algún punto y a pesar de revisar el código una y otra vez no se ve el punto de fallo.
Llegados a esta situación, es el momento de añadir comentarios a lo largo del código para intentar acotar el segmento donde se produce el fallo. Un echo dentro del if y otro en el else, para ver por dónde pasa. Y uno más en el bucle para ver las repeticiones que se producen.
Una vez encontrada y corregida la errata, a buscar todos los comentarios que se insertadon para eliminarlos.
Hay un método mucho más fácil para seguir la pista a la ejecución de un script y ver así cuál es su punto de fallo.

Bash tiene un modo debug que permite la ejecución de un script mostrando mucha información de cada instrucción ejecutada, y mostrando por qué sitios del código pasa. De esta forma, se puede comprender el flujo que sigue la ejecución y determinar con mayor facilidad el error cometido.
Veamos un ejemplo. Dado el script myscript.sh:
#!/usr/bin/env bash

n=0
while [ $n -lt 10 ]
do
        sleep 1
done
Si lo ejecutamos obtendremos un bucle infinito. Algo hace que el script no haga lo que se pretendía, que es simplemente esperar 10 segundos y finalizar su ejecución.
$ ./myscript.sh
Aunque en este ejemplo el fallo es evidente, vamos a ejecutar el script en modo debug usando el parámetro -x en bash:
$ bash -x myscript.sh
+ n=0
+ '[' 0 -lt 10 ']'
+ sleep 1
+ '[' 0 -lt 10 ']'
+ sleep 1
+ '[' 0 -lt 10 ']'
+ sleep 1
+ '[' 0 -lt 10 ']'
+ sleep 1
+ '[' 0 -lt 10 ']'
+ sleep 1...
Detectado el hecho de que siempre estamos comparando si 0 es menor que 10, es el momento de añadir la suma de 1 unidad en cada iteración del bucle.
#!/usr/bin/env bash

n=0
while [ $n -lt 10 ]
do
        sleep 1
        n=$(expr $n + 1)done
Ahora la ejecución ya es exitosa y si usamos el modo debug, veremos el comportamiento deseado:
$ bash -x myscript.sh
+ n=0
+ '[' 0 -lt 10 ']'
+ sleep 1
++ expr 0 + 1
+ n=1
+ '[' 1 -lt 10 ']'
+ sleep 1
++ expr 1 + 1
+ n=2
+ '[' 2 -lt 10 ']'
+ sleep 1
++ expr 2 + 1
+ n=3
+ '[' 3 -lt 10 ']'
+ sleep 1
++ expr 3 + 1
+ n=4
+ '[' 4 -lt 10 ']'
+ sleep 1
++ expr 4 + 1
+ n=5
+ '[' 5 -lt 10 ']'
+ sleep 1
++ expr 5 + 1
+ n=6
+ '[' 6 -lt 10 ']'
+ sleep 1
++ expr 6 + 1
+ n=7
+ '[' 7 -lt 10 ']'
+ sleep 1
++ expr 7 + 1
+ n=8
+ '[' 8 -lt 10 ']'
+ sleep 1
++ expr 8 + 1
+ n=9
+ '[' 9 -lt 10 ']'
+ sleep 1
++ expr 9 + 1
+ n=10
+ '[' 10 -lt 10 ']'
$