Aperçu
Dans ce tutoriel, nous allons examiner les différentes techniques de débogage des scripts shell Bash. Le shell Bash ne fournit aucun débogueur intégré. Cependant, certaines commandes et constructions peuvent être utilisées à cette fin.
Tout d’abord, nous allons discuter des utilisations de la commande set pour les scripts de débogage. Après cela, nous vérifierons quelques cas d’utilisation spécifiques au débogage à l’aide des commandes set et trap. Enfin, nous présenterons quelques méthodes pour déboguer des scripts déjà en cours d’exécution.
Options de débogage Bash
Les options de débogage disponibles dans le shell Bash peuvent être activées et désactivées de plusieurs manières. Dans les scripts, nous pouvons utiliser la commande set ou ajouter une option à la ligne shebang. Cependant, une autre approche consiste à spécifier explicitement les options de débogage dans la ligne de commande lors de l’exécution du script. Plongeons dans la discussion.
2.1. Activation du mode verbeux
Nous pouvons activer le mode verbeux à l’aide du commutateur -v, ce qui nous permet de visualiser chaque commande avant son exécution.
Pour le démontrer, créons un exemple de script:
#! /bin/bashread -p "Enter the input: " valzero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fi
Ce script vérifie si le nombre entré en entrée est positif ou non.
Ensuite, exécutons notre script:
$ bash -v ./positive_check.sh#! /bin/bashread -p "Enter the input: " valEnter the input: -10zero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fiThe input value is not positive.
Comme nous pouvons le remarquer, il imprime chaque ligne du script sur le terminal avant son traitement.
Nous pouvons également ajouter l’option -v dans la ligne shebang:
#! /bin/bash -v
Cela a le même effet que l’appel explicite d’un script à l’aide de bash-v. Un autre équivalent consiste à activer le mode dans un script à l’aide de la commande set:
#! /bin/bashset -v
En fait, nous pouvons utiliser l’une ou l’autre des manières discutées ci-dessus pour activer les différents commutateurs dont nous discuterons désormais.
2.2. Vérification de syntaxe En utilisant le mode noexec
Il peut y avoir des situations où nous pouvons vouloir valider le script syntaxiquement avant son exécution. Si c’est le cas, nous pouvons utiliser le mode noexec en utilisant l’option -n. En conséquence, Bash lira les commandes mais ne les exécutera pas.
Exécutons notre positive_check.sh script en mode noexec:
$ bash -n ./positive_check.sh
Cela produit une sortie vide car il n’y a pas d’erreurs de syntaxe. Maintenant, nous allons modifier un peu notre script et supprimer l’instruction then:
#! /bin/bashread -p "Enter the input: " valzero_val=0if echo "Positive number entered."else echo "The input value is not positive."fi
Ensuite, nous le validerons syntaxiquement avec l’option -n:
$ bash -n ./positive_check_noexec.sh./positive_check_noexec.sh: line 6: syntax error near unexpected token `else'./positive_check_noexec.sh: line 6: ` else'
Comme prévu, cela a généré une erreur car nous avons manqué l’instruction then dans la condition if.
2.3. Débogage En mode xtrace
Dans la section précédente, nous avons testé le script pour les erreurs de syntaxe. Mais pour identifier les erreurs logiques, nous pouvons vouloir tracer l’état des variables et des commandes pendant le processus d’exécution. Dans de tels cas, nous pouvons exécuter le script en mode xtrace (trace d’exécution) en utilisant l’option -x.
Ce mode imprime la trace des commandes pour chaque ligne après leur extension mais avant leur exécution.
Exécutons notre positive_check.sh script en mode trace d’exécution:
$ bash -x ./positive_check.sh+ read -p 'Enter the input: ' valEnter the input: 17+ zero_val=0+ ''+ echo 'Positive number entered.'Positive number entered.
Ici, nous pouvons voir la version étendue des variables sur stdout avant l’exécution. Il est important de noter que les lignes précédées du signe + sont générées par le mode xtrace.
2.4. Identification des variables non définies
Lançons une expérience pour comprendre le comportement par défaut des variables non définies dans les scripts Bash:
#! /bin/bashfive_val=5two_val=2total=$((five_val+tow_val))echo $total
Nous allons maintenant exécuter le script ci-dessus:
$ ./add_values.sh5
Comme nous pouvons le remarquer, il y a un problème: le script s’est exécuté avec succès, mais la sortie est logiquement incorrecte.
Nous allons maintenant exécuter le script avec l’option -u:
$ bash -u ./add_values.sh./add_values.sh: line 4: tow_val: unbound variable
Certes, il y a beaucoup plus de clarté maintenant!
Le script n’a pas pu s’exécuter car la variable tow_val n’est pas définie. Nous avions tapé par erreur two_val comme tow_val lors du calcul du total.
L’option -u traite les variables et paramètres non définis comme une erreur lors de l’extension des paramètres. Par conséquent, nous recevons une notification d’erreur indiquant qu’une variable n’est pas liée à la valeur lors de l’exécution du script avec l’option -u
Cas d’utilisation pour déboguer des scripts Shell
Jusqu’à présent, nous avons vu les différents commutateurs pour déboguer des scripts. Désormais, nous examinerons quelques cas d’utilisation et méthodes pour les implémenter dans des scripts shell.
3.1. Combinaison des options de débogage
Pour obtenir de meilleures informations, nous pouvons combiner les différentes options de la commande set.
Exécutons notre add_values.sh script avec les options -v et -u activées:
$ bash -uv ./add_values.sh#! /bin/bashfive_val=5two_val=2total=$((five_val+tow_val))./add_values.sh: line 4: tow_val: unbound variable
Ici, en activant le mode verbeux avec l’option -u, nous pourrions facilement identifier l’instruction déclenchant l’erreur.
De même, nous pouvons combiner le mode verbose et xtrace pour obtenir des informations de débogage plus précises.
Comme indiqué précédemment, l’option -v affiche chaque ligne avant son évaluation et l’option -x affiche chaque ligne après leur expansion. Par conséquent, nous pouvons combiner les options -x et -v pour voir à quoi ressemblent les instructions avant et après les substitutions de variables.
Maintenant, exécutons notre positive_check.sh script avec les modes -x et -v activés:
$ bash -xv ./positive_check.sh#! /bin/bashread -p "Enter the input: " val+ read -p 'Enter the input: ' valEnter the input: 5zero_val=0+ zero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fi+ ''+ echo 'Positive number entered.'Positive number entered.
On peut observer que les instructions sont imprimées sur stdout avant et après l’expansion variable.
3.2. Débogage de parties spécifiques du Script
Le débogage avec des scripts shell d’option -x ou -v génère une sortie pour chaque instruction sur stdout. Cependant, il peut arriver que nous souhaitions réduire les informations de débogage à des parties spécifiques du script. Nous pouvons y parvenir en activant le mode de débogage avant le démarrage du bloc de code, puis en le réinitialisant à l’aide de la commande set.
Vérifions-le avec un exemple:
#! /bin/bashread -p "Enter the input: " valzero_val=0set -xif then echo "Positive number entered."else echo "The input value is not positive."fiset +xecho "Script Ended"
Ici, nous ne pouvions déboguer que la condition if en utilisant l’instruction set avant le démarrage de la condition. Plus tard, nous pourrions réinitialiser le mode xtrace après la fin du bloc if en utilisant la commande set + x.
Validons-le avec la sortie:
$ ./positive_debug.shEnter the input: 7+ ''+ echo 'Positive number entered.'Positive number entered.+ set +xScript Ended
Certes, la sortie semble moins encombrée.
3.3. Rediriger uniquement la sortie de débogage vers un fichier
Dans la section précédente, nous avons examiné comment limiter le débogage à certaines parties seulement du script. Par conséquent, nous pourrions limiter la quantité de sortie sur stdout.
De plus, nous pouvons rediriger les informations de débogage vers un autre fichier et laisser la sortie du script s’imprimer sur stdout.
Créons un autre script pour le vérifier:
#! /bin/bashexec 5> debug.log PS4='$LINENO: ' BASH_XTRACEFD="5" read -p "Enter the input: " valzero_val=0if then echo "Positive number entered."else echo "The input value is not positive."fi
Tout d’abord, nous avons ouvert le débogage.fichier journal sur le descripteur de fichier (FD) 5 pour l’écriture à l’aide de la commande exec.
Ensuite, nous avons changé la variable shell spéciale PS4. La variable PS4 définit l’invite qui s’affiche lorsque nous exécutons un script shell en mode xtrace. La valeur par défaut de PS4 est +. Nous avons modifié la valeur de la variable PS4 pour afficher les numéros de ligne dans l’invite de débogage. Pour ce faire, nous avons utilisé une autre variable de shell spéciale LINENO.
Plus tard, nous avons affecté le FD 5 à la variable BASH_XTRACEFD. En effet, Bash va maintenant écrire la sortie xtrace sur FD5, c’est-à-dire déboguer.fichier journal. Exécutons le script:
$ bash -x ./debug_logging.sh+ exec+ PS4='$LINENO: '4: BASH_XTRACEFD=5Enter the input: 2Positive number entered.
Comme prévu, la sortie de débogage n’est pas écrite sur le terminal. Bien que, les premières lignes, jusqu’à ce que FD 5 soit affecté à la sortie de débogage ont été imprimées.
De plus, le script crée également un débogage de fichier de sortie.journal, qui contient les informations de débogage:
$ cat debug.log5: read -p 'Enter the input: ' val6: zero_val=07: ''9: echo 'Positive number entered.'
Scripts de débogage Utilisant trap
Nous pouvons utiliser la fonction de trap de DÉBOGAGE de Bash pour exécuter une commande de manière répétitive. La commande spécifiée dans les arguments de la commande trap est exécutée avant chaque instruction suivante du script.
Illustrons cela avec un exemple:
#! /bin/bashtrap 'echo "Line- ${LINENO}: five_val=${five_val}, two_val=${two_val}, total=${total}" ' DEBUGfive_val=5two_val=2total=$((five_val+two_val))echo "Total is: $total"total=0 && echo "Resetting Total"
Dans cet exemple, nous avons spécifié la commande echo pour imprimer les valeurs des variables five_val, two_val et total. Par la suite, nous avons passé cette instruction echo à la commande trap avec le signal de DÉBOGAGE. En effet, avant l’exécution de chaque commande du script, les valeurs des variables sont imprimées.
Vérifions la sortie générée:
$ ./trap_debug.shLine- 3: five_val=, two_val=, total=Line- 4: five_val=5, two_val=, total=Line- 5: five_val=5, two_val=2, total=Line- 6: five_val=5, two_val=2, total=7Total is: 7Line- 7: five_val=5, two_val=2, total=7Line- 7: five_val=5, two_val=2, total=0Resetting Total
Débogage Exécutant déjà des scripts
Jusqu’à présent, nous avons présenté des méthodes pour déboguer les scripts shell lors de leur exécution. Maintenant, nous allons examiner les moyens de déboguer un script déjà en cours d’exécution.
Considérons un exemple de script en cours d’exécution qui exécute le sommeil dans une boucle while infinie:
#! /bin/bashwhile :do sleep 10 & echo "Sleeping for 4 seconds.." sleep 4done
Avec l’aide de la commande pstree, nous pouvons vérifier les processus enfants fourchus par notre script sleep.sh:
$ pstree -pinit(1)─┬─init(148)───bash(149)───sleep.sh(372)─┬─sleep(422) │ ├─sleep(424) │ └─sleep(425) ├─init(213)───bash(214)───pstree(426) └─{init}(7)
Nous avons utilisé une option supplémentaire -p pour imprimer les ID de processus ainsi que les noms de processus. Par conséquent, nous sommes en mesure de réaliser que le script attend la fin des processus enfants (sommeil).
Parfois, nous pouvons vouloir examiner de plus près les opérations effectuées par nos processus. Dans de tels cas, nous pouvons utiliser la commande strace pour tracer les appels système Linux en cours:
$ sudo strace -c -fp 372strace: Process 372 attachedstrace: Process 789 attachedstrace: Process 790 attached^Cstrace: Process 372 detachedstrace: Process 789 detachedstrace: Process 790 detached% time seconds usecs/call calls errors syscall------ ----------- ----------- --------- --------- ----------------100.00 0.015625 5208 3 wait4 0.00 0.000000 0 6 read 0.00 0.000000 0 1 write 0.00 0.000000 0 39 close 0.00 0.000000 0 36 fstat 0.00 0.000000 0 38 mmap 0.00 0.000000 0 8 mprotect 0.00 0.000000 0 2 munmap 0.00 0.000000 0 6 brk 0.00 0.000000 0 16 rt_sigaction 0.00 0.000000 0 20 rt_sigprocmask 0.00 0.000000 0 1 rt_sigreturn 0.00 0.000000 0 6 6 access 0.00 0.000000 0 1 dup2 0.00 0.000000 0 2 getpid 0.00 0.000000 0 2 clone 0.00 0.000000 0 2 execve 0.00 0.000000 0 2 arch_prctl 0.00 0.000000 0 37 openat------ ----------- ----------- --------- --------- ----------------100.00 0.015625 228 6 total
Ici, nous avons utilisé l’option -p pour attacher à l’id de processus (372), c’est-à-dire notre script en exécution. De plus, nous avons également utilisé l’option -f pour l’attacher à tous ses processus enfants. Notez que la commande strace génère une sortie pour chaque appel système. Par conséquent, nous avons utilisé l’option -c pour imprimer un résumé des appels système à la fin de strace.
Conclusion
Dans ce tutoriel, nous avons étudié plusieurs techniques pour déboguer un script shell.
Au début, nous avons discuté des différentes options de la commande set et de leur utilisation pour le débogage des scripts. Après cela, nous avons mis en œuvre plusieurs études de cas pour étudier une combinaison d’options de débogage. Parallèlement à cela, nous avons également exploré des moyens de restreindre la sortie de débogage et de la rediriger vers un autre fichier.
Ensuite, nous avons présenté un cas d’utilisation de la commande trap et du signal de débogage pour les scénarios de débogage. Enfin, nous avons proposé quelques approches pour déboguer des scripts déjà en cours d’exécution.