¿Cómo depurar un script bash?

135

Tengo algunos problemas con algunos scripts en bash, sobre errores y comportamientos inesperados. Me gustaría investigar las causas de los problemas para poder aplicar soluciones. ¿Hay alguna manera de activar algún tipo de "modo de depuración" para bash, para obtener más información?

Braiam
fuente

Respuestas:

132

Inicie su script bash con bash -x ./script.sho agregue su script set -xpara ver la salida de depuración.


Adicional con bash4.1 o posterior:

Si desea escribir la salida de depuración en un archivo separado, agregue esto a su script:

exec 5> debug_output.txt
BASH_XTRACEFD="5"

Ver: https://stackoverflow.com/a/25593226/3776858


Si desea ver los números de línea agregue esto:

PS4='$LINENO: '


Si tiene acceso al loggercomando, puede usar esto para escribir la salida de depuración a través de su registro del sistema con la marca de tiempo, el nombre del script y el número de línea:

#!/bin/bash

exec 5> >(logger -t $0)
BASH_XTRACEFD="5"
PS4='$LINENO: '
set -x

# Place your code here

Puede usar la opción -pde loggercomando para establecer una instalación y un nivel individuales para escribir la salida a través de syslog local en su propio archivo de registro.

Ciro
fuente
77
-v también puede ayudar (imprime cada línea a medida que se ejecutan. se puede combinar con -x). Y vea también: bashdb.sourceforge.net
Olivier Dulac
44
otro recurso maravilloso es: shellcheck.net
Olivier Dulac
¿Qué hace "exec 5>"?
aggsol
3
@aggsol: si utiliza BASH_XTRACEFD="5"bash, escribe la salida de rastreo generada cuando set -xestá habilitada para el descriptor de archivo 5. exec 5> >(logger -t $0)redirige la salida del descriptor de archivo 5 al loggercomando.
Cyrus
1
Me pregunto ¿puedes obtener el número de línea y la ruta o el nombre del script de shell en PS4?
iloveretards
55

Utilizando set -x

Yo siempre uso set -xy set +x. Puede ajustar las áreas que desea ver qué sucede con ellas para aumentar o disminuir la verbosidad.

#!/bin/bash

set -x
..code to debug...
set +x

log4bash

Además, si ha realizado un trabajo de desarrollo y está familiarizado con el estilo de los registradores que llevan los nombres log4j, log4perl, etc., es posible que desee utilizar log4bash .

extracto

Seamos realistas: el viejo y simple eco simplemente no lo corta. log4bash es un intento de tener un mejor registro para los scripts de Bash (es decir, hacer que el inicio de sesión en Bash succione menos).

Desde allí puede hacer cosas como esta en sus scripts de Bash:

#!/usr/bin/env bash
source log4bash.sh

log "This is regular log message... log and log_info do the same thing";

log_warning "Luke ... you turned off your targeting computer";
log_info "I have you now!";
log_success "You're all clear kid, now let's blow this thing and go home.";
log_error "One thing's for sure, we're all gonna be a lot thinner.";

# If you have figlet installed -- you'll see some big letters on the screen!
log_captains "What was in the captain's toilet?";

# If you have the "say" command (e.g. on a Mac)
log_speak "Resistance is futile";

Resultando en este tipo de salida:

    ss1

log4sh

Si necesita algo más portátil, también está el más antiguo log4sh. Funciona de manera similar a log4bash, disponible aquí:

slm
fuente
En Ubuntu, tengo alias say="spd-say"en mi .bashrc, que imita el saycomando de otras distribuciones u OS X.
Doorknob
1
set -vx sería una buena combinación si se usa con trap - trap read debug. Esto le permite pasar línea por línea y ver los resultados
Magnus Melwin
34

Hay un depurador bash, bashdb , que es un paquete instalable en muchas distribuciones. Utiliza el modo de depuración extendida incorporado de bash ( shopt -s extdebug). Se parece mucho a gdb; Aquí hay una sesión de muestra para darle un poco de sabor:

$ ls
1st.JPG  2ndJPG.JPG
$ cat ../foo.sh
for f in *.JPG
do
  newf=${f/JPG/jpg}
  mv $f $newf
done
$ bashdb ../foo.sh
(foo.sh:1):
1:      for f in *.JPG
bashdb<0> next
(foo.sh:3):
3:        newf=${f/JPG/jpg}
bashdb<1> next
(foo.sh:4):
4:        mv $f $newf

Como en gdb, la declaración se muestra justo antes de que se ejecute. Entonces podemos examinar las variables para ver qué hará la declaración antes de que lo haga.

bashdb<2> print $f $newf
1st.JPG 1st.jpg
bashdb<3> next
(foo.sh:1):
1:      for f in *.JPG
bashdb<4> next
(foo.sh:3):
3:        newf=${f/JPG/jpg}
bashdb<5> next
(foo.sh:4):
4:        mv $f $newf
bashdb<6> print $f $newf
2ndJPG.JPG 2ndjpg.JPG

Eso no es lo que queremos! Veamos nuevamente la expansión de parámetros.

bashdb<7> print $f ${f/JPG/jpg}
2ndJPG.JPG 2ndjpg.JPG
bashdb<8> print $f ${f/JPG$/jpg}
2ndJPG.JPG 2ndJPG.JPG
bashdb<9> print $f ${f/%JPG/jpg}
2ndJPG.JPG 2ndJPG.jpg

OK, eso funciona. Vamos a establecer newfel valor correcto.

bashdb<10> eval newf=${f/%JPG/jpg}
$? is 0
bashdb<11> print $f $newf
2ndJPG.JPG 2ndJPG.jpg

Se ve bien. Continuar el guión.

bashdb<12> next
Debugged program terminated normally. Use q to quit or R to restart.
$ ls
1st.jpg  2ndJPG.jpg
Mark Plotnick
fuente
20

El método estándar para depurar scripts en la mayoría de los shells basados ​​en Bourne, como bash, es escribir set -xen la parte superior de su script. Esto hará que bash sea más detallado sobre lo que se está haciendo / ejecutando y cómo se evalúan los argumentos.

-x  Print commands and their arguments as they are executed.

Esto es útil para el intérprete o los guiones internos. Por ejemplo:

$ find "$fileloc" -type f -prune "$filename" -print
+ find /var/adm/logs/morelogs -type f -prune '-name *.user' -print
find: unknown predicate '-name *.user'
$ find "$fileloc" -type f -prune $filename -print
+ find /var/adm/logs/morelogs -type f -prune -name '*.user' -print
find: '/var/adm/logs/morelogs': No such file or directory

En lo anterior podemos ver por qué find falla debido a algunas comillas simples.

Para desactivar la función, simplemente escriba set +x.

Braiam
fuente
13

Usando Eclipse

Puede usar el entorno combinado de Eclipse y Shelled con el script "_DEBUG.sh" vinculado a continuación.

Conchas de cambio

De forma predeterminada, la herramienta de desarrollo Shelled se usa /bin/dashcomo intérprete. Cambié esto para /bin/bashtener una mejor compatibilidad con la mayoría de los ejemplos de shell en la web y mi entorno.

NOTA: Puede cambiar esto yendo a: Ventana -> Preferencia -> Script de Shell -> Intérpretes

Instrucciones de instalación

El paquete Debugger tiene los pasos para usar el _DEBUG.shscript para la depuración de su script, que es básicamente (el archivo readme.txt):

  1. Crear proyecto de script de Shell: Archivo -> Nuevo -> Otro -> Script de Shell -> Asistente de proyecto de script de Shell .
  2. Cree un archivo de script Bash: Archivo -> Nuevo -> Archivo . Para este ejemplo, lo será script.sh. La extensión debe ser ".sh" y es imprescindible.
  3. Copie el archivo _DEBUG.sha la carpeta del proyecto.
  4. Inserte el siguiente texto en la parte superior del archivo script.sh:

    . _DEBUG.sh
  5. Si el archivo se crea en Microsoft Windows, asegúrese de ejecutar el Archivo -> Convertir delimitadores de línea a -> Unix .

  6. Configure una configuración de inicio de depuración: Ejecutar -> Configuraciones de depuración -> Script de Bash ... Hay 2 campos para configurar aquí:

    a) "Script Bash:" - Ruta en el espacio de trabajo de Eclipse al script Bash para depurar.
    e) "Puerto del depurador:" 33333

  7. Cambie a la perspectiva de depuración. Comience la sesión de depuración. Lanzamiento script.shdesde bash shell.

La interfaz de usuario de depuración de bash

ingrese la descripción de la imagen aquí

Este depurador bash tiene las características completas de los depuradores de programación estándar como:

  • Alternar punto de ruptura
  • Operación individual paso a paso
  • Funciones y subrutinas paso a paso, paso a paso, paso a paso
  • Examinar el código o las variables en cualquier momento mientras se ejecuta el script

El IDE (entorno de desarrollo integrado) descascarado (Shell Script Editor) tiene una ventaja adicional de realizar comprobaciones de contexto, resaltar y sangrar mientras escribe su script. Si no sangra correctamente, es posible que pueda marcar / localizar de inmediato muchos errores allí.

Luego hay otros beneficios IDE como:

  • Lista de tareas TODO
  • Mylyn Task
  • Lista de marcadores
  • Edición de múltiples ventanas
  • Intercambio remoto del medio ambiente
LD James
fuente
Punta genial. Es bueno saber que Bash se puede depurar de esta manera.
slm
8

Un recurso maravilloso apareció en los últimos años: http://shellcheck.net

le muestra más de lo que lo hace el bash regular, lo que le permite encontrar fácilmente esas molestas comillas no cerradas o llaves, etc.

Solo asegúrese de no pegar información confidencial (ips, contraseñas, etc.) en la red ... (especialmente porque es http, sin cifrar) (creo que Shellcheck también está disponible para descargar, pero no estoy seguro)

Olivier Dulac
fuente
6

simplemente use:

#!/bin/bash -x

Lo mismo para Shell:

#!/bin/sh -x
Gery
fuente