¿Cómo depurar un script bash?

¿Hay alguna forma de depurar un script bash? Por ejemplo, algo que imprime una especie de registro de ejecución como “línea de llamada 1”, “línea de llamada 2”, etc.

sh -x script [arg1 ...] bash -x script [arg1 ...] 

Estos le dan un rastro de lo que se está ejecutando. (Ver también ‘Aclaración’ cerca de la parte inferior de la respuesta.)

A veces, necesita controlar la depuración dentro del script. En ese caso, como me recordó Cheeto , puedes usar:

 set -x 

Esto activa la depuración. Luego puede apagarlo de nuevo con:

 set +x 

(Puede averiguar el estado de seguimiento actual analizando $- , los indicadores actuales, para x .)

Además, las shells generalmente proporcionan opciones ‘ -n ‘ para ‘no ejecución’ y ‘ -v ‘ para ‘verbose’; puede usarlos en combinación para ver si el intérprete de comandos cree que podría ejecutar su secuencia de comandos, ocasionalmente útil si tiene una cita desequilibrada en alguna parte.


Existe la opinión de que la opción ‘ -x ‘ en Bash es diferente de otras shells (ver los comentarios). El manual de Bash dice:

  • -X

    Imprima un rastro de comandos simples, for comandos, comandos de case , comandos de select y aritmética for comandos y sus argumentos o listas de palabras asociadas después de que se hayan expandido y antes de que se ejecuten. El valor de la variable PS4 se expande y el valor resultante se imprime antes del comando y sus argumentos expandidos.

Eso no parece indicar un comportamiento diferente en absoluto. No veo ninguna otra referencia relevante a ‘ -x ‘ en el manual. No describe las diferencias en la secuencia de inicio.

Aclaración : en sistemas como un cuadro Linux típico, donde ‘ /bin/sh ‘ es un enlace simbólico a ‘ /bin/bash ‘ (o donde se encuentre el ejecutable Bash), las dos líneas de comando logran el efecto equivalente de ejecutar el script con seguimiento de ejecución. En otros sistemas (por ejemplo, Solaris y algunas variantes más modernas de Linux), /bin/sh no es Bash, y las dos líneas de comando darían (ligeramente) diferentes resultados. En particular, ‘ /bin/sh ‘ sería confundido por construcciones en Bash que no reconoce en absoluto. (En Solaris, /bin/sh es un shell Bourne, en el Linux moderno, a veces es Dash, un shell más pequeño, estrictamente POSIX solamente). Cuando se invoca por su nombre de esta manera, la línea ‘shebang’ (‘ #!/bin/bash ‘vs '#!/bin/sh ‘) al comienzo del archivo no tiene ningún efecto sobre cómo se interpretan los contenidos.

El manual de Bash tiene una sección en modo Bash POSIX que, contrariamente a una versión antigua pero errónea de esta respuesta (ver también los comentarios a continuación), describe en detalle la diferencia entre ‘Bash invocado como sh ‘ y ‘Bash invocado como bash ‘.

Al depurar un script de shell (Bash), será sensato y sensato, incluso necesario, para usar el shell nombrado en la línea shebang con la opción -x . De lo contrario, puede (¿tendrá?) Obtener un comportamiento diferente al depurar desde la ejecución del script.

He usado los siguientes métodos para depurar mi script.

set -e hace que el script se detenga inmediatamente si cualquier progtwig externo devuelve un estado de salida distinto de cero. Esto es útil si su secuencia de comandos intenta manejar todos los casos de error y donde una falla al hacerlo debe quedar atrapada.

set -x se mencionó anteriormente y es sin duda el más útil de todos los métodos de depuración.

set -n también puede ser útil si desea verificar si su script tiene errores de syntax.

strace también es útil para ver qué está pasando. Especialmente útil si usted no ha escrito el guión usted mismo.

Esta respuesta es válida y útil: https://stackoverflow.com/a/951352

Pero, considero que los métodos de depuración de scripts “estándar” son ineficaces, poco intuitivos y difíciles de usar. Para aquellos que utilizan sofisticados depuradores GUI que ponen todo a su scope y simplifican el trabajo para problemas fáciles (y posibles problemas difíciles), estas soluciones no son muy satisfactorias.

Lo que hago es usar una combinación de DDD y bashdb. El primero ejecuta el último y el segundo ejecuta el script. Esto proporciona una interfaz de usuario de varias ventanas con la capacidad de desplazarse por el código en contexto y ver variables, astackr, etc., sin el esfuerzo mental constante para mantener el contexto en su cabeza o para volver a enumerar la fuente.

Hay una guía para configurarlo aquí: http://ubuntuforums.org/showthread.php?t=660223

También puede escribir “set -x” dentro del script.

Encontré la utilidad shellcheck y puede ser que algunas personas lo encuentren interesante https://github.com/koalaman/shellcheck

Un pequeño ejemplo:

 $ cat test.sh ARRAY=("hello there" world) for x in $ARRAY; do echo $x done $ shellcheck test.sh In test.sh line 3: for x in $ARRAY; do ^-- SC2128: Expanding an array without an index only gives the first element. 

arregla el error, primero intenta …

 $ cat test.sh ARRAY=("hello there" world) for x in ${ARRAY[@]}; do echo $x done $ shellcheck test.sh In test.sh line 3: for x in ${ARRAY[@]}; do ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces. 

Intentemoslo de nuevo…

 $ cat test.sh ARRAY=("hello there" world) for x in "${ARRAY[@]}"; do echo $x done $ shellcheck test.sh 

¡encuentra ahora!

Es solo un pequeño ejemplo.

Creé un depurador Bash. Solo inténtalo. Espero que ayude https://sourceforge.net/projects/bashdebugingbash

Instale VSCode , luego agregue la extensión de depuración bash y estará listo para depurar en modo visual. mira aquí en acción.

enter image description here

Creo que puedes probar este depurador Bash: http://bashdb.sourceforge.net/ .

set + x = @ECHO OFF, configure -x = @ECHO ON.


Puede agregar la opción -xv al Shebang estándar de la siguiente manera:

 #!/bin/bash -xv 

-x : Muestra los comandos y sus argumentos a medida que se ejecutan.
-v : Muestra líneas de entrada de shell a medida que se leen.


ltrace es otra utilidad de Linux similar a strace . Sin embargo, ltrace enumera todas las llamadas de biblioteca que se ltrace en un ejecutable o en un proceso en ejecución. Su nombre en sí proviene del rastreo de llamadas a bibliotecas. Por ejemplo:

 ltrace ./executable  ltrace -p  

Fuente

Algún truco para depurar scripts bash :

Usando set -[nvx]

Además de

 set -x 

y

 set +x 

para detener el vaciado.

Me gustaría hablar sobre el set -v qué volcado es tan pequeño como el menos desarrollado.

 bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l 21 for arg in xvn nx nv nvx;do echo "- opts: $arg" bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) < 

Variables de volcado o seguimiento sobre la marcha

Para probar algunas variables, uso alguna vez esto:

 bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args 

para añadir:

 declare >&2 -p var1 var2 

en la línea 18 y ejecuta el script resultante (con args ), sin tener que editarlos.

por supuesto, esto podría usarse para agregar el set [+-][nvx] :

 bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args 

agregará declare -p v1 v2 >&2 después de la línea 18, set -x antes de la línea 22 y set +x antes de la línea 26.

pequeña muestra:

 bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <( seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2 arg1 arg2, 1 arg1 arg2, 2 declare -i LINENO="3" declare -- i="2" /dev/fd/63: line 3: declare: v2: not found arg1 arg2, 3 declare -i LINENO="5" declare -- i="3" /dev/fd/63: line 5: declare: v2: not found arg1 arg2, 4 + echo arg1 arg2, 5 arg1 arg2, 5 + echo arg1 arg2, 6 arg1 arg2, 6 + set +x arg1 arg2, 7 arg1 arg2, 8 

Nota: ¡ Cuidar acerca de $LINENO se verá afectado por modificaciones sobre la marcha !

(Para ver la secuencia de comandos resultante sin ejecución, simplemente suelte bash <( y ) arg1 arg2 )

Paso a paso, tiempo de ejecución

Echa un vistazo a mi respuesta sobre cómo crear perfiles de scripts Bash

Usa eclipse con los plugins sin shell y basheclipse.

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

Para el bombardeo: descargue el zip e impórtelo en eclipse a través de la ayuda -> instale un nuevo software: archivo local Para basheclipse: copie los flasks en el directorio dropins del eclipse

Siga los pasos proporcionados https://sourceforge.net/projects/basheclipse/files/?source=navbar

enter image description here

Escribí un tutorial con muchas capturas de pantalla en http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html

Hay una gran cantidad de detalles sobre el inicio de sesión para scripts de shell a través de variables globales de shell. Podemos emular el tipo similar de inicio de sesión en el script de shell: http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

La publicación contiene detalles sobre la introducción de niveles de registro como INFO, DEBUG, ERROR. Detalles de rastreo como entrada de script, salida de script, entrada de función, salida de función.

Registro de muestra:

enter image description here

Mensajes de error de Write Bash

Un script de shell es un archivo de texto que contiene comandos de shell. Por defecto, el intérprete de comandos y las utilidades de shell muestran mensajes de error y diagnóstico en el error estándar. Bash puede imprimir un trazo de una secuencia de comandos en ejecución si la opción xtrace está habilitada.

El código de muestra imprime una traza en el archivo xtrace.log . La función err permite identificar rápidamente los mensajes de error. La traza de la función err se cancela porque su entorno de ejecución actual oculta la información que forma la traza.

Código de muestra

 #!/bin/bash set -o errexit exec 4>xtrace.log BASH_XTRACEFD=4 PS4='+ $0: line ${LINENO}: ${FUNCNAME[0]}: ' set -x echo 'Welcome!' err() { printf "%s\n" "${BASH_SOURCE[0]}: line ${BASH_LINENO[0]}: ${FUNCNAME[0]}: $1" } >&2 4>/dev/null err 'oops, something went wrong!' 

Este código de muestra genera:

 prompt% my_script Welcome ./my_script: line 16: err: oops, something went wrong! 

Los mensajes de error pueden ser redirigidos para ocultar los mensajes de diagnóstico:

 prompt% my_script 2>err.log Welcome! 

Mire la traza y vea los mensajes de error y diagnóstico:

 prompt% cat xtrace.log + ./my_script: line 9: main: echo Welcome + ./my_script: line 16: main: err 'oops, something went wrong!' prompt% cat err.log ./my_script: line 16: err: oops, something went wrong!