
La depuración puede ayudarlo a corregir errores en el programa. En este artículo, discutiremos varios métodos para depurar scripts bash en sistemas operativos Linux y Unix.
introducir
En los primeros días de mi programación, pasé algunas horas tratando de encontrar el error en el código y, al final, podría ser simple. Es posible que se haya encontrado con la misma situación.
Saber cómo utilizar las técnicas de depuración adecuadas le ayudará a resolver los errores rápidamente. A diferencia de otros lenguajes como Python y Java, bash no tiene una herramienta de depuración, donde puede establecer puntos de interrupción, omitir código, etc.
Hay algunas funciones integradas para ayudar a depurar los scripts de shell de bash. Aprenderemos más sobre estas características en las siguientes secciones.
Tres formas de utilizar las opciones de depuración
Cuando desee habilitar las opciones de depuración en un script, puede hacerlo de tres formas.
1Habilite las opciones de depuración desde el shell del terminal al invocar el script.
$ bash [ debugging flags ] scriptname
2Habilite las opciones de depuración pasando indicadores de depuración a la línea shebang en el script.
#!/bin/bash [ debugging flags ]
3. Habilite la opción de depuración usando set
Comando del guión.
set -o nounset
set -u
¿Cuál es el uso del comando Establecer?
Esta set
El comando es un comando de shell incorporado que se puede usar para controlar los parámetros de bash y cambiar el comportamiento de bash de alguna manera.
Normalmente, no ejecutará el comando set desde la terminal para cambiar el comportamiento de su shell. Será ampliamente utilizado en scripts de shell para depurar o para habilitar el modo estricto bash.
$ type -a set
set is a shell builtin
Puede visitar la sección de ayuda del comando set para saber qué indicadores admite y qué hace cada indicador.
$ set --help
Depurar secuencia de comandos parcial o completa
Antes de comprender las opciones de depuración, debe comprender que puede depurar todo el script o solo una parte del código. Debe utilizar el comando set para habilitar y deshabilitar las opciones de depuración.
set -
Se habilitará el modo de depuración.set +
El modo de depuración se desactivará.
Eche un vistazo al código a continuación. set -x
Habilitará el modo xtrace para el script y set +x
El modo xtrace se desactivará.Cualquier cosa en el medio set -x
y set +x
Se ejecutará en modo de depuración de xtrace.
Aprenderá sobre el modo xtrace en la siguiente sección. Entonces, para cualquier indicador de depuración, lo único que debe recordar es, set -
Habilitará el modo y set +
Este modo estará desactivado.
#!/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}
Si la variable no está definida, falla
Cuando con Variables en bash, La desventaja es que si intentamos usar variables indefinidas, el script no fallará y mostrará algunos mensajes de error, como «Variable indefinida»En cambio, imprimirá una cadena vacía.
Eche un vistazo al código a continuación, obtengo información del usuario y la almaceno en una variable $OBJECT
. Estoy intentando ejecutar el operador de prueba (-f
y -d
) existe $OBJECT1
Variable indefinida.
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
Cuando ejecuto este código, debería arrojarme un error, pero no es así, incluso el código de retorno es cero cuando sale el script.
Para anular este comportamiento, use -u
Se lanzará una bandera incorrecta cuando se utilicen variables indefinidas.
Ejecutaré el mismo código nuevamente con el nombre de variable incorrecto, pero esta vez arrojará un «Variable no consolidada» Error.
También puede configurar -u
Opción de uso set
Ordene o páselo como parámetro a shebang.
set -u
set -o nounset
(o)
#! /bin/bash -u
El modo Xtrace puede ayudarte
Este es un modo que uso mucho al depurar errores lógicos en scripts bash. pista El modo mostrará el código línea por línea, pero con parámetros extendidos.
En la sección anterior, cuando no estaba -u
Firmar, se ha completado con éxito, pero espero la salida en la terminal. Ahora puedo ejecutar el mismo script en modo xtrace y ver exactamente dónde ocurrió el problema en el script.
Eche un vistazo al código de muestra a continuación.
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
Cuando ejecuté el código anterior, no devolvió ningún resultado.
Para depurar este problema, puedo pista Modo pasado -x
bandera.
En el resultado a continuación, puede ver que las variables se expanden y se imprimen.Esto me dice que hay una cadena vacía asignada a la declaración condicional -f
y -d
De esta forma puedo comprobar y corregir errores de forma lógica.
El signo más que ve en la salida se puede configurar PS4
Variables en el guión. De forma predeterminada, PS4 está configurada en (+
).
$ echo $PS4
+
$ PS4=" ==> " bash -x debugging.sh
También puede usar el comando set para configurar el modo Xtrace o pasarlo como parámetro a shebang.
set -x
set -o xtrace
(o)
#! /bin/bash -x
De manera similar, al depurar, puede redirigir los registros de depuración de Xtrace a un archivo en lugar de imprimirlos en la terminal.
Eche un vistazo al código a continuación.Asigno el descriptor de archivo 6 a .log
Archivos y BASH_XTRACEFD="6"
Redirija el registro de depuración de xtrace al descriptor de archivo 6.
#!/bin/bash exec 6> redirected_debug.log PS4=' ==> ' BASH_XTRACEFD="6" read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
Cuando ejecuto este código en lugar de imprimir la salida de xtrace en la terminal, será redirigido a .log
documento.
$ cat redirected_debug.log ==> read -p 'Please provide the object name : ' OBJECT ==> [[ -f '' ]] ==> [[ -d '' ]]
Estado de salida de PIPE
El comportamiento predeterminado cuando se utiliza una canalización es que adoptará el código de salida del último comando ejecutado en la canalización. Incluso si falla el comando anterior en la canalización, ejecutará el resto de la canalización.
Eche un vistazo al siguiente ejemplo.Intento abrir un archivo no disponible y uso El recuento de palabras programa.a pesar de que cat
El comando arroja un error y se ejecuta el programa de recuento de palabras.
Si intenta verificar el código de salida de la última vez que ejecutó el comando de canalización con el siguiente comando $?
, Obtendrá cero como código de salida del programa de recuento de palabras.
$ cat nofile.txt | wc -l cat: nofile.txt: No such file or directory 0
$ echo $?
Cuando pipefail está habilitado en el script, si algún comando arroja un código de retorno distinto de cero en la canalización, se trata como el código de retorno de toda la canalización. Puede habilitar pipefail agregando el siguiente atributo de conjunto en el script.
set -o pipefail
Todavía hay problemas con este enfoque. Por lo general, se debe esperar que si falla algún comando en la canalización, el script se cierre sin ejecutar los comandos restantes en la canalización.
Desafortunadamente, incluso si falla algún comando, se ejecutarán los comandos subsiguientes en la canalización. Esto se debe a que cada comando de la canalización se ejecuta en su propia subcapa. El shell esperará a que se completen todos los procesos en la canalización y luego devolverá el resultado.
Bash modo estricto
Para eliminar todos los posibles errores que vimos en la sección anterior, se recomienda agregar las siguientes opciones a cada script.
Hemos discutido todas estas opciones en detalle en la sección anterior.
-e flag
=> Si algún comando arroja un código de salida distinto de cero, salga del script.-u flag
=> Si se usa un nombre de variable indefinido, el script fallará.pipefail
=> Si falla algún comando en la tubería, se considerará el código de salida de toda la tubería.IFS
=> Separador de campo interno, configurándolo en salto de línea ( n) y ( t) hará que la división solo ocurra en saltos de línea y tabulaciones.
set -e
set -u
set -o pipefail
o
set -euo pipefail
IFS=$'nt'
Usa TRAP para capturar la señal
trampa Le permite capturar la señal en un script bash y realizar algunas acciones en consecuencia.
Piense en el escenario en el que activa la secuencia de comandos pero desea cancelar la secuencia de comandos con el siguiente comando CTRL+C
Pulsaciones de teclas. Bajo estas circunstancias, SIGINT
Se enviará a tu script. Puede captar esta señal y ejecutar algunos comandos o funciones.
Eche un vistazo al pseudocódigo que se proporciona a continuación.Creé una función llamada limpieza, que estará en SIGINT
Páselo al guión.
trap 'cleanup' TERM INT function cleanup(){ echo "Running cleanup since user initiated CTRL + C"}
Puede utilizar la trampa «DEBUG», que se puede utilizar para ejecutar una instrucción repetidamente en un script. Se comporta de tal manera que cada instrucción que se ejecute en la trampa del script ejecutará la función o instrucción asociada.
Puede utilizar el siguiente ejemplo para comprender esto.
#!/bin/bash trap 'printf "${LINENO} ==> DIR_NAME=${D_OBJECT} ; FILE_NAME=${F_OBJECT}; FILE_CREATED=${FILE_C} n"' DEBUG read -p "Pass Dir name : " D_OBJECT read -p "Pass File name : " F_OBJECT touch ${D_OBJECT}/${F_OBJECT} && FILE_C="Yes" exit 0
Este es un programa simple que toma la entrada del usuario y crea archivos y directorios. El comando trap se ejecutará para cada declaración en el script e imprimirá los parámetros pasados y el estado de creación del archivo.
Mira el siguiente resultado. Para cada línea del script, se activa una trampa y las variables se actualizan en consecuencia.
Utilice el modo detallado para imprimir código
En modo detallado, el código se imprimirá antes de devolver el resultado. Si el programa requiere una entrada interactiva en este caso, la línea se imprimirá por separado, seguida de un bloque de código.
Eche un vistazo al programa a continuación.Es un programa simple que obtiene un objeto del usuario y usa Declaraciones condicionales.
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT ]] then echo "$OBJECT is a directory" fi
Cuando ejecuto el código anterior, primero imprime el código y luego espera la entrada del usuario, como se muestra a continuación.
Una vez que paso el objeto, el resto del código se imprimirá y luego se enviará.
También puede configurar el modo detallado usando set
O en shebang
.
set -v
set -o verbose
(o)
#! /bin/bash -v
También puede combinar el modo detallado con otros modos.
set -vx # Verbose and Xtrace Mode
set -uv # Verbose and Unset Mode
Verificación de sintaxis-modo noexec
Hasta ahora, hemos visto cómo manejar los errores lógicos en los scripts. En esta sección, analicemos los errores gramaticales.
Los errores de sintaxis son muy comunes en los programas. Es posible que se haya perdido la referencia o no haya podido salir del bucle, etc. puedes usarlo»-n
«Ser conocido como el signo noexec mode
Verifique la sintaxis antes de ejecutar el programa.
Ejecutaré el siguiente código y verificaré la sintaxis.
#!/bin/bash TOOLS=( htop peek tilix vagrant shutter ) for TOOL in "${TOOLS[@]" do echo "--------------INSTALLING: ${TOOL}---------------------------" apt install ${TOOL} -y #done
Hay dos errores en este programa. Primero que nada, no cerré «for loop
«En segundo lugar done
La palabra clave está comentada, debe marcar el final del ciclo.
Cuando ejecuto este programa, recibo el siguiente mensaje de error que indica que falta grandes paréntesis y Palabras clave completasA veces, el número de línea señalado en el mensaje de error no contiene ningún error, debe buscar a su alrededor para encontrar el error real.
$ bash -n ./debugging.sh ./debugging.sh: line 6: unexpected EOF while looking for matching `"' ./debugging.sh: line 8: syntax error: unexpected end of file
Cabe señalar que, de forma predeterminada, cuando ejecuta un script, bash validará la sintaxis y arrojará estos errores incluso si no usa el modo noexec.
Alternativamente, también puede usar set
Uso de comando o shebang noexec
modelo.
set -n set -o noexec
o,
#! /bin/bash -n
Hay algunas herramientas externas que vale la pena consultar para depurar scripts.Una de esas herramientas es Inspección de la cáscaraShellcheck también se puede integrar con editores de texto populares, como vscode, sublime text y Atom.
en conclusión
En este artículo, le mostré algunas formas de depurar scripts de bash. A diferencia de otros lenguajes de programación, bash no tiene herramientas de depuración más que algunas opciones integradas. A veces, estas opciones de depuración integradas son suficientes para realizar el trabajo.