Comment déboguer un script bash?

135

J'ai des problèmes avec certains scripts de bash, des erreurs et des comportements inattendus. Je voudrais étudier les causes des problèmes afin que je puisse appliquer des correctifs. Existe-t-il un moyen de transformer une sorte de "mode débogage" pour bash, pour obtenir plus d'informations?

Braiam
la source

Réponses:

132

Lancez votre script bash avec bash -x ./script.shou ajoutez-le dans votre script set -xpour voir la sortie de débogage.


Supplémentaire avec bash4.1 ou plus tard:

Si vous voulez écrire la sortie de débogage dans un fichier séparé, ajoutez ceci à votre script:

exec 5> debug_output.txt
BASH_XTRACEFD="5"

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


Si vous voulez voir les numéros de ligne, ajoutez ceci:

PS4='$LINENO: '


Si vous avez accès à la loggercommande, vous pouvez l'utiliser pour écrire la sortie de débogage via votre syslog avec l'horodatage, le nom du script et le numéro de ligne:

#!/bin/bash

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

# Place your code here

Vous pouvez utiliser l'option -pde loggercommande pour définir une installation et un niveau individuels afin d'écrire la sortie via son syslog local dans son propre fichier journal.

Cyrus
la source
7
-v peut aussi aider (affiche chaque ligne à mesure qu'elle est exécutée. peut être combinée avec -x). Et voir aussi: bashdb.sourceforge.net
Olivier Dulac
4
Une autre ressource merveilleuse est: shellcheck.net
Olivier Dulac
Que fait "exec 5>"?
aggsol
3
@aggsol: Si vous utilisez BASH_XTRACEFD="5"bash, le résultat de la trace généré set -xest activé dans le descripteur de fichier 5. exec 5> >(logger -t $0)redirige le résultat du descripteur de fichier 5 vers la loggercommande.
Cyrus
1
Vous vous demandez simplement si vous pouvez obtenir le numéro de ligne et le chemin ou le nom du script shell sur PS4?
iloveretards
55

En utilisant set -x

J'utilise toujours set -xet set +x. Vous pouvez envelopper les zones que vous voulez voir ce qui se passe avec elles pour activer / désactiver la verbosité.

#!/bin/bash

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

log4bash

De même, si vous avez déjà travaillé sur le développement et connaissez le style des enregistreurs nommés log4j, log4perl, etc., vous voudrez peut-être utiliser log4bash .

extrait

Regardons les choses en face - le vieil écho ne fait tout simplement pas l'affaire. log4bash est une tentative visant à améliorer la journalisation des scripts Bash (c’est-à-dire que la journalisation dans Bash est moins bonne).

À partir de là, vous pouvez faire ce genre de chose dans vos scripts 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";

Résultat dans ce type de sortie:

    ss1

log4sh

Si vous avez besoin de quelque chose de plus portable, il y a aussi le plus vieux log4sh. Fonctionne comme log4bash, disponible ici:

slm
la source
Sur Ubuntu, j'ai alias say="spd-say"dans mon .bashrc, qui imite la saycommande d'autres distributions ou OS X.
Poignée de porte
1
set -vx serait une bonne combinaison si elle est utilisée avec trap - debug read debug. Cela vous permet d’intervenir ligne par ligne et de voir les résultats
Magnus Melwin
34

Il existe un débogueur bash, bashdb , qui est un paquet installable sur de nombreuses distributions. Il utilise le mode de débogage étendu intégré de bash ( shopt -s extdebug). Cela ressemble beaucoup à gdb; voici un exemple de session pour donner un peu de saveur:

$ 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

Comme dans gdb, l'instruction est affichée juste avant son exécution. Nous pouvons donc examiner les variables pour voir ce que l’instruction fera avant de le faire.

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

Ce n'est pas ce que nous voulons! Regardons à nouveau l'expansion des paramètres.

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, ça marche. Réglons newfla valeur correcte.

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

Cela semble bon. Continuez le script.

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

La méthode standard pour déboguer des scripts dans la plupart des shells basés sur Bourne, comme bash, consiste à écrire set -xen haut de votre script. Ceci fera que bash sera plus détaillé sur ce qui est fait / exécuté et comment les arguments sont évalués.

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

c'est utile pour l'interpréteur ou les scripts internes. Par exemple:

$ 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

Dans ce qui précède, nous pouvons voir pourquoi find échoue en raison de guillemets simples.

Pour désactiver la fonctionnalité, tapez simplement set +x.

Braiam
la source
13

Utiliser Eclipse

Vous pouvez utiliser l'environnement combiné d'Eclipse et Shelled avec le script "_DEBUG.sh" lié ci-dessous.

Changer de coquille

Par défaut, l'outil de développement Shelled utilise /bin/dashl'interpréteur. J'ai changé cela pour /bin/bashavoir une meilleure compatibilité avec la plupart des exemples de shell sur le Web et dans mon environnement.

NOTE: Vous pouvez changer cela en allant dans: Fenêtre -> Préférences -> Script shell -> Interprètes

Instructions d'installation

Le paquet de _DEBUG.shdébogage a les étapes pour utiliser le script pour votre débogage de script qui est essentiellement (le fichier readme.txt):

  1. Créer un projet de script shell: Fichier -> Nouveau -> Autre -> Script shell -> Assistant Projet de script shell .
  2. Créez un fichier de script Bash: Fichier -> Nouveau -> Fichier . Pour cet exemple, ce sera script.sh. L'extension devrait être ".sh" et est un must.
  3. Copiez le fichier _DEBUG.shdans le dossier du projet.
  4. Insérez le texte suivant en haut du fichier script.sh:

    . _DEBUG.sh
  5. Si le fichier est créé dans Microsoft Windows, veillez à exécuter le fichier -> Convertir les séparateurs de ligne en -> Unix .

  6. Configurez une configuration de lancement de débogage: Exécuter -> Configurations de débogage -> Script Bash ... Il y a 2 champs à définir ici:

    a) "Script Bash:" - Chemin dans l'espace de travail d'Eclipse vers le script Bash à déboguer.
    e) "Port du débogueur:" 33333

  7. Basculez vers la perspective de débogage. Démarrer la session de débogage. Lancement script.shdepuis shell bash.

L'interface de débogage bash

entrez la description de l'image ici

Ce débogueur bash a toutes les fonctionnalités des débogueurs de programmation standard tels que:

  • Point de rupture bascule
  • Opération unique pas à pas
  • Fonctions et sous-routines pas à pas, pas à pas, pas à pas
  • Examen du code ou des variables à tout moment pendant l'exécution du script

L' environnement de développement intégré (IDE) Shelled (Shell Script Editor) présente un avantage supplémentaire, qui consiste à vérifier le contexte, à mettre en surbrillance et à mettre en retrait tout en écrivant votre script. Si le retrait n’est pas correct, vous pourrez immédiatement signaler / localement de nombreuses erreurs.

Ensuite, il y a d' autres avantages de l'IDE tels que:

  • TODO liste de tâches
  • Mylyn Task
  • Liste de signets
  • Édition de plusieurs fenêtres
  • Partage à distance de l'environnement
LD James
la source
Astuce cool. C'est bien de savoir que Bash peut être débogué comme ça.
slm
8

Une merveilleuse ressource est apparue ces dernières années: http://shellcheck.net

il vous en montre plus que le bash habituel, vous permettant de trouver facilement ces citations embarrassantes ou ces accolades, etc.

Assurez-vous simplement de ne pas coller des informations sensibles (ips, mots de passe, etc.) sur le net ... (d'autant plus qu'il s'agit de http, non cryptées) (je pense que shellcheck est également disponible au téléchargement, mais je ne suis pas sûr)

Olivier Dulac
la source
6

simplement utiliser:

#!/bin/bash -x

la même chose pour shell:

#!/bin/sh -x
Gery
la source
6

De nos jours, il existe le débogage VS Code Bash.

https://marketplace.visualstudio.com/items?itemName=rogalmic.bash-debug

Il a «Pas à pas / plus / plus» et montre également la valeur de chaque variable.

Capture d'écran de VS Code Bash Debug

Henrique Lemos Ribeiro
la source
cette réponse n'aborde pas la question dans le bon contexte; en supposant que la ligne de commande ne soit pas mentionnée dans IDE
qodeninja