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.
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.
Réponses:
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.
-x
L'option « » de Bash est différente des autres shells (voir les commentaires). Le manuel Bash dit:
-X
Imprimez une trace des commandes simples, des for
commandes, des case
commandes, des select
commandes et des for
commandes 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 PS4
variable 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/sh
n'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/sh
est 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' -x
option. Sinon, vous pouvez (obtiendrez?) Un comportement différent lors du débogage de lors de l'exécution du script.
bash
script. Et exécuter un script bash avec le sh -x
fera se comporter complètement différent! Veuillez mettre à jour votre réponse.
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
J'ai utilisé les méthodes suivantes pour déboguer mon script.
set -e
arrê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.
strace
est également utile pour voir ce qui se passe. Particulièrement utile si vous n'avez pas écrit le script vous-même.
strace -f
est 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).
set -e
est ... controversé .
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
Vous pouvez également écrire "set -x" dans le script.
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.
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
J'ai écrit un tutoriel avec de nombreuses captures d'écran sur http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html
J'ai construit un débogueur Bash. Essayez-le. J'espère que cela aidera https://sourceforge.net/projects/bashdebugingbash
set + x = @ECHO OFF, set -x = @ECHO ON.
Vous pouvez ajouter une -xv
option 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.
ltrace
est un autre utilitaire Linux similaire à strace
. Cependant, ltrace
ré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>
Je pense que vous pouvez essayer ce débogueur Bash: http://bashdb.sourceforge.net/ .
set -[nvx]
En plus de
set -x
et
set +x
pour arrêter le vidage.
Je voudrais parler d'un set -v
dump 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
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 >&2
après la ligne 18, set -x
avant la ligne 22 et set +x
avant la ligne 26.
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 $LINENO
sera affecté par les modifications à la volée !
(Pour voir le script résultant sans s'exécuter, déposez simplement bash <(
et ) arg1 arg2
)
Jetez un œil à ma réponse sur la façon de profiler les scripts bash
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: