¿Cómo depurar un script bash? [cerrado]

159

¿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.

corvus
fuente
2
Aquí hay una pregunta similar: serverfault.com/questions/16204/…
hasta nuevo aviso.

Respuestas:

195
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 del final 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 nuevamente con:

set +x

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

Además, los shells generalmente proporcionan opciones ' -n' para 'no ejecución' y ' -v' para modo 'detallado'; puede usarlos en combinación para ver si el shell cree que podría ejecutar su script, ocasionalmente útil si tiene una cita desequilibrada en alguna parte.


Existe la opinión de que la -xopción ' ' en Bash es diferente de otras shells (ver los comentarios). El Manual de Bash dice:

  • -X

    Imprima una traza de comandos simples, forcomandos, casecomandos, selectcomandos y forcomandos aritméticos y sus argumentos o listas de palabras asociadas después de que se expanden y antes de que se ejecuten. El valor de la PS4variable 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 diferencias en la secuencia de inicio.

Aclaración : en sistemas como un cuadro típico de Linux, 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 el seguimiento de ejecución activado. En otros sistemas (por ejemplo, Solaris, y algunas variantes más modernas de Linux), /bin/shno es Bash, y las dos líneas de comando darían resultados (ligeramente) diferentes. En particular, ' /bin/sh' estaría confundido por construcciones en Bash que no reconoce en absoluto. (En Solaris, /bin/shes un shell Bourne; en Linux moderno, a veces es Dash, un shell más pequeño, más estrictamente solo POSIX). Cuando se invoca por un nombre como este, la línea 'shebang' (' #!/bin/bash' vs '#!/bin/sh'

El manual de Bash tiene una sección sobre el modo Bash POSIX que, al contrario de una versión antigua pero errónea de esta respuesta (ver también los comentarios a continuación), describe en gran 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, utilizar el shell nombrado en la línea shebang con la -xopción. De lo contrario, puede (¿tendrá?) Obtener un comportamiento diferente al depurar al ejecutar el script.

Jonathan Leffler
fuente
1
Él especificó un bashguión. ¡Y ejecutar un script bash con sh -xhará que se comporte completamente diferente! Por favor actualice su respuesta.
lhunath
1
@lhunath: ¿De qué manera 'sh -x' (o 'bash -x') hace que un script se comporte de manera completamente diferente? Obviamente, envía información de rastreo a stderr; eso es un hecho (aunque no se menciona en mi respuesta). Pero que mas? Uso 'bash' como 'sh' en Linux y MacOS X y no he notado un problema grave.
Jonathan Leffler
66
Hay diferencias, en el inicio y en tiempo de ejecución. Están completamente documentados en la distribución Bash.
TheBonsai
44
Aquí hay un enlace al documento bash: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Si Bash se invoca con el nombre sh, intenta imitar el comportamiento de inicio de las versiones históricas de sh como lo más cerca posible, a la vez que se ajusta al estándar posix también '
thethinman
66
Y use el indicador de PS4 para dar más información útil como:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani
28

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

set -ehace que el script se detenga inmediatamente si algún programa 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 en caso de que no lo logre quedar atrapado.

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

set -n También podría ser útil si desea verificar su secuencia de comandos en busca de errores de sintaxis.

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


fuente
1
Aplicar un script a un script (es decir, crear un shell ejecutando el script) es un método de depuración de shell extraño (pero puede funcionar para un conjunto limitado de problemas).
TheBonsai
1
Admito que es extraño y también muy detallado, pero si limita la salida de strace a unas pocas llamadas al sistema, se vuelve útil.
1
Tenga en cuenta que strace -fes necesario si también desea encontrar errores en los procesos iniciados por el script. (lo que lo hace mucho más detallado, pero sigue siendo útil si lo limita a las llamadas al sistema que le interesan).
Random832
set -ees ... controversiales .
Charles Duffy el
12

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

Pero, encuentro que los métodos de depuración de script "estándar" son ineficientes, poco intuitivos y difíciles de usar. Para aquellos acostumbrados a depuradores de GUI sofisticados que ponen todo a su alcance y hacen que el trabajo sea fácil para problemas fáciles (y posibles para 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 segundo, y el segundo ejecuta su script. Esto proporciona una interfaz de usuario de múltiples ventanas con la capacidad de recorrer el código en contexto y ver variables, apilar, etc., sin el esfuerzo mental constante de mantener el contexto en su cabeza o seguir enumerando la fuente.

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

Stabledog
fuente
Acabo de descubrir ddd gracias a tu respuesta. En Ubuntu 12.04.3 (64 bits), la versión de apt-sources no funciona. Tuve que compilar e instalar desde la fuente para comenzar a depurar mi script bash. Las instrucciones aquí - askubuntu.com/questions/156906/… ayudaron.
Chronodekar
Si, eso es un problema. Lo resolví hace tiempo con algunas secuencias de comandos: 'dddbash' instala / construye DDD, elimina la versión anterior si es incorrecta, instala bashdb, etc. (La respuesta se ha editado con esta información ahora)
Stabledog
10

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

Cheeto
fuente
44
Y puede escribir 'set + x' para desactivarlo.
Jonathan Leffler
10

Encontré la utilidad Shellcheck y puede 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.

corrige 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.

Solucionador de ecuaciones
fuente
1
¡Y está en línea !
Nick Westgate
Afortunadamente, la herramienta ha evolucionado hasta el punto en que también encuentra el error restante.
tripleee
3

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

ingrese la descripción de la imagen aquí

yantaq
fuente
3

Use eclipse con los complementos sin cáscara y basheclipse.

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

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

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

ingrese la descripción de la imagen aquí

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

Dietrich Schroff
fuente
2
Esta es una respuesta límite de solo enlace (ver también aquí ). Debería ampliar su respuesta para incluir tanta información como sea posible, al menos el mínimo necesario para lograr lo que está sugiriendo, y usar los enlaces solo como referencia. Básicamente, las publicaciones en Stack Overflow (y todo Stack Exchange) deben ser independientes. Eso significa que debe haber suficiente información en su respuesta para que el lector no tenga que ir fuera del sitio para recibir instrucciones. En este momento, ese no es el caso para esta respuesta.
Makyen
Esta es la primera respuesta que he encontrado después de ver muchas que realmente muestran que es posible una depuración verdadera. Las respuestas estándar "set + x" coinciden perfectamente con una respuesta autónoma, pero ignoran casi deliberadamente las preguntas verdaderas sobre la depuración verdadera. Aplaudo esta respuesta 👏
simbo1905
2

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

abadjm
fuente
Actualmente, BDB es compatible con los idiomas inglés y español. Para cambiar el idioma, edite el archivo / etc / default / bdb
abadjm el
la captura de pantalla parece interesante pero no pude hacer que se ejecute "bdb.sh: línea 32: bdbSTR [1]: variable independiente"; Por cierto, ¿mostrará los valores actuales de todas las variables establecidas en cada paso que hacemos en el código?
Acuario Power
2

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


Puede agregar una -xvopción 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 las líneas de entrada del shell a medida que se leen.


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

ltrace ./executable <parameters>  
ltrace -p <PID>  

Fuente

Premraj
fuente
1

Algún truco para depurar guiones:

Utilizando set -[nvx]

Además de

set -x

y

set +x

para detener el volcado.

Me gustaría hablar sobre qué set -vvolcado es tan pequeño como un resultado 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 x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

Volcado de variables o rastreo 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 en funcionamiento resultante de la escritura (con args ), sin tener que modificarlas.

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

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

se agregará declare -p v1 v2 >&2después de la línea 18, set -xantes de la línea 22 y set +xantes 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: ¡La preocupación $LINENOse verá afectada por las modificaciones sobre la marcha !

(Para ver el script resultante sin ejecutar, simplemente suelte bash <(y ) arg1 arg2)

Paso a paso, tiempo de ejecución

Echa un vistazo a mi respuesta sobre cómo perfilar scripts de bash

F. Hauri
fuente
0

Hay una buena cantidad de detalles sobre el registro de scripts de shell a través de varaibles 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 tiene detalles sobre niveles de registro de introducción como INFO, DEBUG, ERROR. Detalles de seguimiento como entrada de script, salida de script, entrada de función, salida de función.

Registro de muestra:

ingrese la descripción de la imagen aquí

Piyush Chordia
fuente