Debug shell

De wiki.nexiat.fr
Aller à la navigation Aller à la recherche
Fiche express
Domaine Débogage / traçage d'un script shell
Trace commande par commande set -x
Arrêt sur erreur set -e
Variable non définie = erreur set -u
Voir aussi Bash · Trap

Déboguer un script shell consiste à observer ce qu'il exécute réellement (et avec quelles valeurs de variables) sans forcément le modifier — Bash fournit plusieurs options intégrées pour ça, complétées par quelques techniques de journalisation.

Options de shell (set)

set -x   # affiche chaque commande (avec les substitutions déjà faites) avant de l'exécuter
set -v   # affiche chaque ligne du script telle qu'elle est lue, avant substitution
set -e   # arrête le script dès qu'une commande retourne un code non nul
set -u   # erreur si une variable non définie est utilisée (au lieu de la traiter comme vide)
set -o pipefail   # un pipeline échoue si une seule de ses commandes échoue (pas seulement la dernière)

Ces options se combinent (set -eux) et se retirent avec un + à la place du - (set +x pour arrêter la trace). Il est courant de les activer/désactiver ponctuellement autour d'une section sensible plutôt que pour tout le script :

# section normale
set -x
# section à tracer
commande_a_verifier
set +x
# retour à la normale

Le préfixe affiché par -x peut être personnalisé via PS4 (utile pour dater chaque ligne ou afficher le numéro de ligne) :

export PS4='+ [${LINENO}] '
set -x

Capturer stdout et stderr tout en les affichant

Technique pour journaliser l'intégralité de la sortie d'un script dans un fichier sans perdre l'affichage à l'écran (utile en exécution interactive comme en cron) : rediriger le descripteur 1 vers un named pipe lu par tee, puis rediriger le descripteur 2 vers le descripteur 1.

exec > >(tee /tmp/install.log)   # stdout : dupliqué vers tee (écran + fichier)
exec 2>&1                        # stderr : redirigé vers le même flux que stdout

L'ordre compte : la deuxième ligne doit venir après la première pour que stderr suive stdout vers tee, sinon stderr continue de sortir directement à l'écran sans passer par le fichier.

Arrêt propre sur erreur

set -e arrête le script au premier échec, mais certains contextes le désactivent implicitement (une commande dans une condition if, un pipeline sans pipefail, une commande suivie de ||). Pour un nettoyage garanti même en cas d'arrêt brutal ou de signal, préférer un trap sur EXIT — voir Trap.

Voir aussi

  • Bash — syntaxe générale, variables spéciales ($?, $LINENO)
  • Trap — interception de signaux et nettoyage garanti à la sortie d'un script