Tutoriales

Debug Bash script-OSTechNix

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.

Secuencia de comandos completada con éxito

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.

Variable no consolidada
Variable no consolidada

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.

error lógico
error lógico

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 -dDe esta forma puedo comprobar y corregir errores de forma lógica.

Modo de seguimiento
Modo de seguimiento

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
Establecer o cambiar variables de PS4
Establecer o cambiar variables de PS4

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 $?
0

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
Estado de salida de PIPE
Estado de salida de PIPE

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.

Ejecute TRAP para cada declaración
Ejecute TRAP para cada declaración

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.

Modo detallado
Modo detallado

Una vez que paso el objeto, el resto del código se imprimirá y luego se enviará.

Utilice el modo detallado para imprimir código
Utilice el modo detallado para imprimir código

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.

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba