Comment déboguer un script bash? [fermé]

159

Existe-t-il un moyen de déboguer un script bash? Par exemple, quelque chose qui imprime une sorte de journal d'exécution comme "appelant la ligne 1", "appelant la ligne 2" etc.

corvus
la source
2
Il y a une question similaire ici: serverfault.com/questions/16204/…
pause jusqu'à nouvel ordre.

Réponses:

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

Ceux-ci vous donnent une trace de ce qui est en cours d'exécution. (Voir aussi «Clarification» en bas de la réponse.)

Parfois, vous devez contrôler le débogage dans le script. Dans ce cas, comme Cheeto me l'a rappelé , vous pouvez utiliser:

set -x

Cela active le débogage. Vous pouvez ensuite le désactiver à nouveau avec:

set +x

(Vous pouvez trouver l'état de traçage actuel en analysant $-, les indicateurs actuels, pour x.)

De plus, les shells fournissent généralement les options « -n» pour «aucune exécution» et « -v» pour le mode «verbeux»; vous pouvez les utiliser en combinaison pour voir si le shell pense pouvoir exécuter votre script - parfois utile si vous avez un devis déséquilibré quelque part.


-xL'option « » de Bash est différente des autres shells (voir les commentaires). Le manuel Bash dit:

  • -X

    Imprimez une trace des commandes simples, des forcommandes, des casecommandes, des selectcommandes et des forcommandes arithmétiques et de leurs arguments ou des listes de mots associés après leur développement et avant leur exécution. La valeur de la PS4variable est développée et la valeur résultante est imprimée avant la commande et ses arguments développés.

Cela ne semble pas du tout indiquer un comportement différent. Je ne vois aucune autre référence pertinente à « -x» dans le manuel. Il ne décrit pas les différences dans la séquence de démarrage.

Clarification : sur des systèmes tels qu'une machine Linux typique, où « /bin/sh» est un lien symbolique vers « /bin/bash» (ou partout où se trouve l'exécutable Bash), les deux lignes de commande obtiennent l'effet équivalent de l'exécution du script avec la trace d'exécution activée. Sur d'autres systèmes (par exemple, Solaris et certaines variantes plus modernes de Linux), ce /bin/shn'est pas Bash, et les deux lignes de commande donneraient des résultats (légèrement) différents. Plus particulièrement, ' /bin/sh' serait dérouté par des constructions dans Bash qu'il ne reconnaît pas du tout. (Sur Solaris, /bin/shest un shell Bourne; sur Linux moderne, il s'agit parfois de Dash - un shell plus petit, plus strictement réservé à POSIX.) Lorsqu'elle est appelée par un nom comme celui-ci, la ligne 'shebang' (' #!/bin/bash' vs '#!/bin/sh'

Le manuel Bash contient une section sur le mode Bash POSIX qui, contrairement à une version ancienne mais erronée de cette réponse (voir aussi les commentaires ci-dessous), décrit en détail la différence entre `` Bash invoqué comme sh'' et `` Bash invoqué comme bash».

Lors du débogage d'un script shell (Bash), il sera judicieux et sensé - nécessaire même - d'utiliser le shell nommé dans la ligne shebang avec l' -xoption. Sinon, vous pouvez (obtiendrez?) Un comportement différent lors du débogage de lors de l'exécution du script.

Jonathan Leffler
la source
1
Il a spécifié un bashscript. Et exécuter un script bash avec le sh -xfera se comporter complètement différent! Veuillez mettre à jour votre réponse.
lhunath le
1
@lhunath: En quoi 'sh -x' (ou 'bash -x') fait-il qu'un script se comporte complètement différemment? De toute évidence, il envoie des informations de trace à stderr; c'est une donnée (mais non mentionnée dans ma réponse). Mais quoi d'autre? J'utilise «bash» comme «sh» sous Linux et MacOS X et je n'ai pas remarqué de problème sérieux.
Jonathan Leffler
6
Il existe des différences, au démarrage et à l'exécution. Ils sont entièrement documentés dans la distribution Bash.
TheBonsai
4
Voici un lien vers le bash doc: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Si Bash est appelé avec le nom sh, il essaie d'imiter le comportement de démarrage des versions historiques de sh comme aussi étroitement que possible, tout en se conformant également à la norme posix '
thethinman
6
Et utilisez l'invite PS4 pour donner des informations plus utiles comme:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani
28

J'ai utilisé les méthodes suivantes pour déboguer mon script.

set -earrête immédiatement le script si un programme externe renvoie un statut de sortie différent de zéro. Ceci est utile si votre script tente de gérer tous les cas d'erreur et lorsqu'un échec de le faire doit être intercepté.

set -x a été mentionnée ci-dessus et est certainement la plus utile de toutes les méthodes de débogage.

set -n peut également être utile si vous souhaitez vérifier votre script pour les erreurs de syntaxe.

straceest également utile pour voir ce qui se passe. Particulièrement utile si vous n'avez pas écrit le script vous-même.


la source
1
Le suivi d'un script (c'est-à-dire le suivi d'un shell exécutant le script) est une étrange méthode de débogage du shell (mais peut fonctionner pour un ensemble limité de problèmes).
TheBonsai
1
J'avoue que c'est étrange et aussi très verbeux, mais si vous limitez la sortie de strace à quelques appels système, cela devient utile.
1
Notez que cela strace -fest nécessaire si vous souhaitez également rechercher des erreurs dans les processus démarrés par le script. (ce qui le rend beaucoup plus verbeux, mais toujours utile si vous le limitez aux appels système qui vous intéressent).
Random832
set -eest ... controversé .
Charles Duffy
12

Cette réponse est valide et utile: https://stackoverflow.com/a/951352

Mais, je trouve que les méthodes de débogage de script "standard" sont inefficaces, peu intuitives et difficiles à utiliser. Pour ceux qui sont habitués aux débogueurs GUI sophistiqués qui mettent tout à portée de main et facilitent le travail pour les problèmes faciles (et possibles pour les problèmes difficiles), ces solutions ne sont pas très satisfaisantes.

Ce que je fais, c'est utiliser une combinaison de DDD et bashdb. Le premier exécute le second et le second exécute votre script. Cela fournit une interface utilisateur multi-fenêtres avec la possibilité de parcourir le code en contexte et d'afficher les variables, la pile, etc., sans l'effort mental constant pour maintenir le contexte dans votre tête ou continuer à réinscrire la source.

Il y a des conseils sur la configuration ici: http://ubuntuforums.org/showthread.php?t=660223

Stabledog
la source
Je viens de découvrir ddd grâce à ta réponse. Dans Ubuntu 12.04.3 (64 bits), la version apt-sources ne fonctionne pas. J'ai dû compiler et installer à partir des sources pour commencer à déboguer mon script bash. Les instructions ici - askubuntu.com/questions/156906/… ont aidé.
chronodekar
Oui, c'est un problème. Je l'ai résolu il y a quelque temps avec des scripts - 'dddbash' installe / construit DDD, supprime l'ancienne version si elle est fausse, installe bashdb, etc. (La réponse a été modifiée avec cette information maintenant)
Stabledog
10

Vous pouvez également écrire "set -x" dans le script.

Cheeto
la source
4
Et vous pouvez écrire «set + x» pour le désactiver.
Jonathan Leffler
10

J'ai trouvé l'utilitaire shellcheck et certains le trouvent peut-être intéressant https://github.com/koalaman/shellcheck

Un petit exemple:

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

corrigez le bogue, essayez d'abord ...

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

Essayons encore...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

trouve maintenant!

C'est juste un petit exemple.

Solveur d'équations
la source
1
Et c'est en ligne !
Nick Westgate le
Heureusement, l'outil a évolué au point où il trouve également le bogue restant.
tripleee
3

Installez VSCode , puis ajoutez l'extension de débogage bash et vous êtes prêt à déboguer en mode visuel. voir Ici en action.

entrez la description de l'image ici

yantaq
la source
3

Utilisez eclipse avec les plugins shelled & basheclipse.

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

Pour shelled: Téléchargez le zip et importez-le dans eclipse via l'aide -> installez un nouveau logiciel: archive locale Pour basheclipse: Copiez les jars dans le répertoire dropins d'eclipse

Suivez les étapes fournies https://sourceforge.net/projects/basheclipse/files/?source=navbar

entrez la description de l'image ici

J'ai écrit un tutoriel avec de nombreuses captures d'écran sur http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html

Dietrich Schroff
la source
2
Ceci est une réponse à la limite des liens uniquement (voir également ici ). Vous devriez élargir votre réponse pour inclure ici autant d'informations que possible, au moins le minimum nécessaire pour accomplir réellement ce que vous suggérez, et utiliser les liens uniquement à titre de référence. Fondamentalement, les publications sur Stack Overflow (et l'ensemble de Stack Exchange) doivent être autonomes. Cela signifie que votre réponse doit contenir suffisamment d'informations pour que le lecteur n'ait pas besoin de quitter le site pour obtenir des directions. À l'heure actuelle, ce n'est pas le cas pour cette réponse.
Makyen
c'est la première réponse que j'ai trouvée après en avoir examiné beaucoup qui montre en fait qu'un véritable débogage est possible. Les réponses standard "set + x" correspondent parfaitement à une réponse autonome mais ignorent presque volontairement les vraies questions sur le vrai débogage. J'applaudis cette réponse 👏
simbo1905
2

J'ai construit un débogueur Bash. Essayez-le. J'espère que cela aidera https://sourceforge.net/projects/bashdebugingbash

abadjm
la source
BDB est actuellement pris en charge en anglais et en espagnol. Pour changer la langue, éditez le fichier / etc / default / bdb
abadjm
la capture d'écran semble intéressante mais je n'ai pas pu la faire exécuter "bdb.sh: ligne 32: bdbSTR [1]: variable non liée"; btw montrera-t-il les valeurs actuelles de toutes les variables définies à chaque étape que nous faisons sur le code?
Aquarius Power
2

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


Vous pouvez ajouter une -xvoption au Shebang standard comme suit:

#!/bin/bash -xv  

-x: Affiche les commandes et leurs arguments au fur et à mesure de leur exécution.
-v: Affiche les lignes d'entrée du shell au fur et à mesure de leur lecture.


ltraceest un autre utilitaire Linux similaire à strace. Cependant, ltracerépertorie tous les appels de bibliothèque appelés dans un exécutable ou un processus en cours d'exécution. Son nom lui-même vient du traçage des appels de bibliothèque. Par exemple:

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

La source

Premraj
la source
1

Une astuce pour déboguer scripts:

En utilisant set -[nvx]

En plus de

set -x

et

set +x

pour arrêter le vidage.

Je voudrais parler d'un set -vdump aussi petit que d'une sortie moins développée.

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

Vider les variables ou le traçage à la volée

Pour tester certaines variables, j'utilise parfois ceci:

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

pour ajouter:

declare >&2 -p var1 var2

à la ligne 18 et exécutant le script résultant (avec args ), sans avoir à les éditer.

bien sûr, cela pourrait être utilisé pour ajouter set [+-][nvx]:

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

ajoutera declare -p v1 v2 >&2après la ligne 18, set -xavant la ligne 22 et set +xavant la ligne 26.

petit échantillon:

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

Remarque: Care about $LINENOsera affecté par les modifications à la volée !

(Pour voir le script résultant sans s'exécuter, déposez simplement bash <(et ) arg1 arg2)

Pas à pas, temps d'exécution

Jetez un œil à ma réponse sur la façon de profiler les scripts bash

F. Hauri
la source
0

Il y a une bonne quantité de détails sur la journalisation des scripts shell via des variables globales de shell. Nous pouvons émuler le même type de journalisation dans un script shell: http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

Le message contient des détails sur l'introduction de niveaux de journal tels que INFO, DEBUG, ERROR. Traçage des détails tels que l'entrée de script, la sortie de script, l'entrée de fonction, la sortie de fonction.

Exemple de journal:

entrez la description de l'image ici

Piyush Chordia
la source