Le débogage vous aide à corriger les erreurs dans votre programme. Dans cet article, nous aborderons différentes méthodes pour déboguer les scripts bash dans les systèmes d'exploitation Linux et Unix.
Présentation
Au cours de mes premiers jours de programmation, j'ai passé des heures à essayer de trouver l'erreur dans mon code, et à la fin, cela pourrait être quelque chose de simple. Vous avez peut-être aussi été confronté à la même situation.
Savoir utiliser la technique de débogage appropriée vous aiderait à résoudre les erreurs rapidement. Contrairement à d'autres langages comme Python, Java, etc., il n'y a pas d'outil de débogage pour bash où vous pouvez définir des points d'arrêt, parcourir le code, etc.
Certaines fonctionnalités intégrées aident à déboguer les scripts shell bash. Nous allons voir en détail ces fonctionnalités dans les sections à venir.
Trois façons d'utiliser les options de débogage
Lorsque vous souhaitez activer les options de débogage dans vos scripts, vous pouvez le faire de trois manières.
1 . Activez les options de débogage à partir du shell du terminal lors de l'appel du script.
$ bash [ debugging flags ] scriptname
2 . Activez les options de débogage en passant les drapeaux de débogage à la ligne shebang dans le script.
#!/bin/bash [ debugging flags ]
3 . Activez les options de débogage en utilisant le set
commande du script.
set -o nounset
set -u
À quoi sert la commande Set ?
L'set
command est une commande intégrée du shell qui peut être utilisée pour contrôler les paramètres bash et modifier le comportement bash de certaines manières.
Normalement, vous n'exécuterez pas de commandes set à partir du terminal pour modifier le comportement de votre shell. Il sera largement utilisé dans les scripts shell, soit pour le débogage, soit pour activer le mode bash strict.
$ type -a set
set is a shell builtin
Vous pouvez accéder à la section d'aide de la commande set pour savoir quels indicateurs elle prend en charge et ce que fait chaque indicateur.
$ set --help
Déboguer une partie du script ou du script complet
Avant d'en savoir plus sur les options de débogage, vous devez comprendre que vous pouvez soit déboguer le script entier, soit seulement une certaine partie du code. Vous devez utiliser la commande set pour activer et désactiver les options de débogage.
set -<debugging-flag>
activera le mode débogage.set +<debugging-flag>
désactivera le mode débogage.
Jetez un oeil au code ci-dessous. set -x
activera le mode xtrace pour le script et set +x
désactivera le mode xtrace. Tout ce qui vient entre set -x
et set +x
s'exécutera en mode de débogage xtrace.
Vous en apprendrez plus sur le mode xtrace dans la prochaine section. Donc, pour tout indicateur de débogage, la seule chose dont vous devez vous souvenir est, set -
activera le mode et set +
désactivera le mode.
#!/bin/bash set -x read -p "Pass Dir name : " D_OBJECT read -p "Pass File name : " F_OBJECT set +x touch ${D_OBJECT}/${F_OBJECT}
Échec si aucune variable n'est définie
Lorsque vous travaillez avec des variables dans bash , l'inconvénient est que si nous essayons d'utiliser une variable indéfinie, le script n'échouera pas avec un message d'erreur comme "Variable non définie" . Au lieu de cela, il imprimera une chaîne vide.
Jetez un oeil au code ci-dessous où je reçois l'entrée de l'utilisateur et la stocke dans la variable $OBJECT
. J'ai essayé d'exécuter l'opérateur de test (-f
et -d
) sur le $OBJECT1
variable qui n'est pas définie.
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
Lorsque j'exécute ce code, il aurait dû me renvoyer une erreur, mais ce n'est pas le cas et même le script s'est terminé avec le code de retour zéro.
Pour remplacer ce comportement, utilisez le -u
drapeau qui lancera une erreur lorsqu'une variable indéfinie est utilisée.
Je vais exécuter à nouveau le même code avec le mauvais nom de variable, mais cette fois, il lancera une "variable non liée" erreur.
Vous pouvez également définir le -u
option en utilisant le set
commande ou passez-la comme argument au shebang.
set -u
set -o nounset
(ou)
#! /bin/bash -u
Le mode Xtrace à la rescousse
C'est le mode que j'utilise largement lorsque je débogue des scripts bash pour les erreurs logiques. Xtrace affichera le code ligne par ligne mais avec des paramètres développés.
Dans la section précédente, lorsque j'ai exécuté le code sans le -u
flag, il s'est terminé avec succès mais j'attendais la sortie dans le terminal. Maintenant, je peux exécuter le même script en mode xtrace et voir exactement où le problème se produit dans le script.
Jetez un oeil à l'exemple de code suivant.
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
Lorsque j'exécute le code ci-dessus, il ne me renvoie aucune sortie.
Pour déboguer ce problème, je peux exécuter le script dans xtrace mode en passant le -x
drapeau.
Dans la sortie ci-dessous, vous pouvez voir que les variables sont développées et imprimées. Cela me dit qu'il y a des chaînes vides assignées aux instructions conditionnelles -f
et -d
. De cette façon, je peux logiquement vérifier et corriger les erreurs.
Le signe plus que vous voyez dans la sortie peut être modifié en définissant le PS4
variables dans le script. Par défaut, la PS4 est définie sur (+
).
$ echo $PS4
+
$ PS4=" ==> " bash -x debugging.sh
Vous pouvez également définir le mode Xtrace à l'aide de la commande set ou le transmettre comme argument au shebang.
set -x
set -o xtrace
(ou)
#! /bin/bash -x
De même, lors du débogage, vous pouvez rediriger les journaux de débogage Xtrace vers un fichier au lieu de les imprimer sur le terminal.
Jetez un oeil au code ci-dessous. J'attribue un descripteur de fichier 6 au .log
fichier et BASH_XTRACEFD="6"
redirigera les journaux de débogage xtrace vers le descripteur de fichier 6.
#!/bin/bash exec 6> redirected_debug.log PS4=' ==> ' BASH_XTRACEFD="6" read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT1 ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT1 ]] then echo "$OBJECT is a directory" fi
Lorsque j'exécute ce code au lieu d'imprimer la sortie xtrace dans le terminal, il sera redirigé vers le .log
fichier.
$ cat redirected_debug.log ==> read -p 'Please provide the object name : ' OBJECT ==> [[ -f '' ]] ==> [[ -d '' ]]
État de sortie PIPE
Le comportement par défaut lors de l'utilisation d'un tube est qu'il prendra le code de sortie de la dernière commande d'exécution dans le tube. Même si les commandes précédentes du tube ont échoué, le reste du tube sera exécuté.
Jetez un oeil à l'exemple ci-dessous. J'ai essayé d'ouvrir un fichier qui n'est pas disponible et de le canaliser avec un nombre de mots programme. Même si le cat
génère une erreur, le programme de comptage de mots s'exécute.
Si vous essayez de vérifier le code de sortie de la dernière commande run pipe en utilisant $?
, vous obtiendrez zéro comme code de sortie qui provient du programme de comptage de mots.
$ cat nofile.txt | wc -l cat: nofile.txt: No such file or directory 0
$ echo $? 0
Lorsque pipefail est activé dans le script, si une commande renvoie un code de retour différent de zéro dans le tube, il sera considéré comme le code de retour pour l'ensemble du pipeline. Vous pouvez activer pipefail en ajoutant la propriété set suivante dans votre script.
set -o pipefail
Il y a toujours un problème avec cette approche. Normalement, ce à quoi on devrait s'attendre est que si une commande dans le tube échoue, le script doit se terminer sans exécuter le reste de la commande dans le tube.
Mais malheureusement, même si une commande échoue, la commande suivante dans le tuyau s'exécute. En effet, chaque commande du tube s'exécute dans son propre sous-shell. Le shell attendra que tous les processus du tube soient terminés, puis renverra le résultat.
Mode strict bash
Pour éliminer toutes les erreurs possibles que nous avons vues dans les sections précédentes, il est recommandé d'ajouter les options suivantes dans chaque script.
Nous avons déjà discuté en détail de toutes ces options dans la section précédente.
-e flag
=> Quitter le script si une commande génère un code de sortie non nul.-u flag
=> Faire échouer le script si un nom de variable non défini est utilisé.pipefail
=> Si une commande du pipeline échoue, le code de sortie sera pris en compte pour l'ensemble du pipeline.IFS
=> Séparateur de champ interne, le définir sur nouvelle ligne (\n) et (\t) fera que la division ne se produira que dans la nouvelle ligne et la tabulation.
set -e
set -u
set -o pipefail
Ou
set -euo pipefail
IFS=$'\n\t'
Capturer des signaux à l'aide de TRAP
Piège vous permet de capturer des signaux vers votre script bash et de prendre certaines mesures en conséquence.
Pensez à un scénario où vous déclenchez le script mais que vous souhaitez annuler le script en utilisant CTRL+C
frappe. Dans ce cas, SIGINT
sera envoyé à votre script. Vous pouvez capturer ce signal et exécuter certaines commandes ou fonctions.
Jetez un œil au pseudo-code ci-dessous. J'ai créé une fonction appelée nettoyage qui s'exécutera lorsque SIGINT
est passé au script.
trap 'cleanup' TERM INT function cleanup(){ echo "Running cleanup since user initiated CTRL + C" <some logic> }
Vous pouvez utiliser le trap "DEBUG", qui peut être utilisé pour exécuter une instruction à plusieurs reprises dans le script. La façon dont il se comporte est que chaque instruction qui s'exécute dans l'interruption de script exécutera la fonction ou l'instruction associée.
Vous pouvez comprendre cela en utilisant l'exemple ci-dessous.
#!/bin/bash trap 'printf "${LINENO} ==> DIR_NAME=${D_OBJECT} ; FILE_NAME=${F_OBJECT}; FILE_CREATED=${FILE_C} \n"' DEBUG read -p "Pass Dir name : " D_OBJECT read -p "Pass File name : " F_OBJECT touch ${D_OBJECT}/${F_OBJECT} && FILE_C="Yes" exit 0
Il s'agit d'un programme simple qui obtient l'entrée de l'utilisateur et crée un fichier et un répertoire. La commande trap s'exécutera pour chaque instruction du script et imprimera les arguments passés et l'état de création du fichier.
Découvrez la sortie ci-dessous. Pour chaque ligne du script, le trap est déclenché et les variables sont mises à jour en conséquence.
Imprimer le code en mode verbeux
En mode verbeux, le code sera imprimé avant de renvoyer le résultat. Si le programme nécessite une entrée interactive, dans ce cas, seule cette ligne sera imprimée suivie d'un bloc de codes.
Jetez un oeil au programme suivant. C'est un programme simple qui obtient un objet de l'utilisateur et vérifie si l'objet passé est un fichier ou un répertoire en utilisant une instruction conditionnelle .
#!/bin/bash read -p "Please provide the object name : " OBJECT if [[ -f $OBJECT ]] then echo "$OBJECT is a file" elif [[ -d $OBJECT ]] then echo "$OBJECT is a directory" fi
Lorsque j'exécute le code ci-dessus, il imprime d'abord le code, puis attend la saisie de l'utilisateur, comme indiqué ci-dessous.
Une fois que j'ai passé l'objet, le reste du code sera imprimé suivi de la sortie.
Vous pouvez également définir le mode verbeux en utilisant set
ou en shebang
.
set -v
set -o verbose
(ou)
#! /bin/bash -v
Vous pouvez également combiner le mode détaillé avec d'autres modes.
set -vx # Verbose and Xtrace Mode
set -uv # Verbose and Unset Mode
Validation de la syntaxe - mode noexec
Jusqu'à présent, nous avons vu comment travailler avec des erreurs logiques dans le script. Dans cette section, parlons des erreurs de syntaxe.
Les erreurs de syntaxe sont très courantes dans les programmes. Vous avez peut-être manqué une citation ou n'avez pas réussi à sortir de la boucle, etc. Vous pouvez utiliser le "-n
" indicateur appelé noexec mode
pour valider la syntaxe avant d'exécuter le programme.
Je vais exécuter le morceau de code ci-dessous et valider la syntaxe.
#!/bin/bash TOOLS=( htop peek tilix vagrant shutter ) for TOOL in "${TOOLS[@]" do echo "--------------INSTALLING: ${TOOL}---------------------------" apt install ${TOOL} -y #done
Il y a deux erreurs dans ce programme. Tout d'abord, je n'ai pas réussi à fermer les accolades dans la "for loop
" et deuxièmement done
le mot-clé est commenté, ce qui devrait marquer la fin de la boucle.
Lorsque j'exécute ce programme, j'obtiens les messages d'erreur suivants indiquant qu'il manque des accolades et mot-clé terminé . Parfois, le numéro de ligne pointé dans le message d'erreur ne contiendra aucune erreur que vous devriez rechercher pour trouver l'erreur réelle.
$ bash -n ./debugging.sh ./debugging.sh: line 6: unexpected EOF while looking for matching `"' ./debugging.sh: line 8: syntax error: unexpected end of file
Il est à noter que, par défaut, lorsque vous exécutez le script, bash validera la syntaxe et lancera ces erreurs même sans utiliser le mode noexec.
Alternativement, vous pouvez également utiliser le set
commande ou shebang pour utiliser le noexec
mode.
set -n set -o noexec
Ou,
#! /bin/bash -n
Il existe quelques outils externes qui valent la peine d'être utilisés pour déboguer les scripts. L'un de ces outils est Shellcheck . Shellcheck peut également être intégré à des éditeurs de texte populaires tels que vscode, sublime text, Atom.
Conclusion
Dans cet article, je vous ai montré quelques-unes des façons de déboguer les scripts bash. Contrairement à d'autres langages de programmation, bash n'a pas d'outils de débogage autres que certaines options intégrées. Parfois, ces options de débogage intégrées seront plus que suffisantes pour faire le travail.
Guides de script bash :
- Scripts bash :analyse des arguments dans les scripts bash à l'aide de getops
- Comment créer des boîtes de dialogue GUI dans des scripts Bash avec Zenity sous Linux et Unix
- Scripts bash – Énoncé de cas
- Scripts bash – Instructions conditionnelles
- Scripts bash – Manipulation de chaînes
- Scripts bash – Explication de la commande Printf à l'aide d'exemples
- Scripts bash – Tableau indexé expliqué à l'aide d'exemples
- Scripts bash - Tableau associatif expliqué avec des exemples
- Scripts bash – Explication de la boucle For avec des exemples
- Scripts bash :boucle While et Until expliquée à l'aide d'exemples
- La redirection bash expliquée avec des exemples
- Scripts bash – Variables expliquées à l'aide d'exemples
- Scripts bash – Fonctions expliquées à l'aide d'exemples
- La commande Bash Echo expliquée avec des exemples sous Linux
- Tutoriel Bash Heredoc pour les débutants