E-NO
Dépannage Bash 8 min de lecture

Dépannage Bash avec des exemples pratiques : guide d’implémentation

calendar_today Publié : 2026-07-17
update Dernière mise à jour : 2026-07-17
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Dépannage Bash avec des exemples pratiques : guide d’implémentation ».

Introduction

Bash est la colle qui tient ensemble de nombreux jobs de build, de release et d’exploitation. Quand cela échoue, l’impact peut être large. Ce guide, entièrement pratique, fournit un workflow reproductible, des extraits prêts à l’emploi, des commandes sûres, des interprétations de résultats et des mesures de retour arrière. Vous pourrez l’appliquer localement, dans Docker et Docker Compose, et à l’intérieur de pods Kubernetes.

Prérequis et zone de sécurité

Avant tout dépannage, mettez en place un cadre qui évite les dégâts et facilite le retour arrière.

  • Version de Bash et shell effectif
  • Vérifiez la version et le shell utilisé :
    bash --version
    printf '%s\n' "$BASH_VERSION"
    echo "$SHELL"; ps -o comm= -p $$
  • À interpréter : assurez-vous d’exécuter Bash et non un autre shell (p. ex. dash).
  • Répertoire de travail et permissions
  • Confirmez le répertoire courant et l’accessibilité :
    pwd; id; umask; ls -la
  • Zone de test et sauvegardes
  • Travaillez sur une copie, jamais sur des données de production directement :
    cp -a projet "projet.bak.$(date +%Y%m%d-%H%M%S)"
  • Utilisez des options non destructives (--dry-run, -n, -i) tant que le correctif n’est pas validé.
  • Journalisation séparée et horodatée
  • Préparez-vous à capturer stdout, stderr et une trace set -x distincte.

Workflow de dépannage reproductible

Suivez ce flux, du symptôme au correctif validé et documenté.

  1. Capturer le symptôme
  • Notez la commande exacte, ses arguments, le répertoire courant et le code de sortie :
  failing_cmd arg1 arg2 1>out.log 2>err.log; echo $? > exit.code
  • Enregistrez la version de Bash :
  bash --version; printf '%s\n' "$BASH_VERSION"
  1. Réduire l’échec au plus petit repro
  • Isolez le fragment minimal qui échoue encore.
  • Remplacez les dépendances externes par des fakes/fixtures.
  1. Tracer et journaliser (granulaire)
  • Tracez seulement autour des lignes suspectes :
  {
    exec {XTRACE_FD}>trace.log
    export BASH_XTRACEFD=$XTRACE_FD
    export PS4='+ ${EPOCHREALTIME} ${BASH_SOURCE}:${LINENO}: '
    set -x
    do_thing
    set +x
    exec {XTRACE_FD}>&-
  } 2>/dev/null
  • Évitez de tracer autour des secrets :
  set +x; token="${TOKEN:?missing TOKEN}"; set -x
  1. Vérifier les causes racines probables
  • Suivez la check-list ci-dessous (PATH, guillemets, permissions, fins de ligne, pipelines…).
  1. Appliquer une correction sûre
  • Privilégiez les options non destructives, les --dry-run, les fichiers temporaires (mktemp), et une portée limitée des garde-fous.
  1. Prouver et documenter
  • Rejouez le repro minimal puis le script original.
  • Conservez les artefacts (logs, trace, diff) et ajoutez un test/README pour éviter la régression.

Collecte des logs (claire et exploitable)

De bons logs répondent à quoi a échoué, où et pourquoi, sans secrets involontaires.

  • Capture de base
  failing_cmd 1>stdout.log 2>stderr.log; echo $? > exit.code
  • Trace complète dans un descripteur séparé (pour ne pas mélanger avec la sortie fonctionnelle)
  exec {XTRACE_FD}>trace.log
  export BASH_XTRACEFD=$XTRACE_FD
  export PS4='+ ${EPOCHREALTIME} ${BASH_SOURCE}:${LINENO}: '
  set -x
  failing_cmd || true
  set +x
  exec {XTRACE_FD}>&-
  • Garder les secrets hors des logs
  set +x
  KEY="${API_KEY:?missing}"
  set -x
  • Logs de conteneur et de cluster
  # Docker
  docker logs mycontainer 2>&1 | tee container.log

  # Docker Compose
  docker compose logs svc -f

  # Kubernetes
  kubectl logs pod/my-pod -c my-container --timestamps
  • Instantané d’environnement (sans secrets)
  ( env | grep -Ev 'KEY|SECRET|TOKEN|PASS' ) | sort > env.snapshot

Vérifications de cause racine (check-list)

Ciblez d’abord les classes d’échecs courantes avant d’explorer des hypothèses rares.

  • PATH et résolution de commande
  which mycmd || type -a mycmd || echo 'missing'
  hash -r
  printf '%s\n' "$PATH" | tr ':' '\n'

À interpréter : type -a liste les résolutions et fonctions/alias ; hash -r purge le cache si des binaires ont bougé.

  • Shebang et différences de shell
  head -1 script.sh   # attendre : #!/usr/bin/env bash
  bash -n script.sh   # vérif de syntaxe
  bash script.sh      # forcer Bash si /bin/sh -> dash
  • Permissions et exécutables
  chmod +x script.sh
  file script.sh      # détecte CRLF
  # Si CRLF :
  dos2unix script.sh || sed -i 's/\r$//' script.sh
  • Guillemets et globbing
  echo "$var"                      # expansions sûres
  set -f; printf '%s\n' $user_input; set +f
  printf '%s\n' "$user_input"     # préférable : toujours citer
  • Pipelines et codes de sortie
  set -o pipefail
  foo | bar | baz; ec=$?; echo "pipeline exit=$ec"
  printf '%s\n' "${PIPESTATUS[@]}"  # statuts individuels
  # Si un non-match de grep est acceptable :
  grep -q pattern file || true
  • Variables non liées et valeurs par défaut
  set -u
  name="${NAME:-anonymous}"
  api="${API_URL:?API_URL is required}"
  • Boucles sûres pour stdin
  while IFS= read -r line; do
    printf 'line: %s\n' "$line"
  done < input.txt
  • Fichiers temporaires et concurrence
  f=$(mktemp) || exit 1
  trap 'rm -f "$f"' EXIT
  # utiliser "$f" en toute sécurité ici

Commandes sûres et garde-fous

Préférez les opérations non destructives pendant la récupération et encadrez les effets de bord.

  • Dry-runs et no-clobber
  rsync -av --dry-run src/ dst/
  cp -an src/ dst/      # -n no-clobber, -a préservation
  mv -i old new         # -i confirmation
  rm -i file            # confirmation
  • Sauvegardes et points de contrôle
  cp -a dir "dir.bak.$(date +%Y%m%d-%H%M%S)"
  • Garde-fous locaux (portée réduite)
  do_safe() {
    set -euo pipefail   # attention : modifie la sémantique d’échec
    "$@"
  }

À interpréter : évitez d’activer set -euo pipefail globalement sans impact analysis ; encapsulez-le dans une fonction/bloc contrôlé.

  • Limitation de débit et timeouts
  timeout 10s long_running || echo 'timed out'

Mesures de retour arrière (rollback)

Protégez-vous contre les faux positifs et les correctifs risqués.

  • Sauvegarde avant modification
  cp -a script.sh "script.sh.bak.$(date +%s)"
  • Écriture sûre puis bascule atomique
  tmp=$(mktemp) && cp script.sh "$tmp" && sed -e 's/old/new/' "$tmp" > "$tmp.edited" \
    && mv -f "$tmp.edited" script.sh
  • Revenir en arrière rapidement
  mv -f script.sh.bak.* script.sh 2>/dev/null || true
  # Dans un dépôt Git
  git restore --source=HEAD -- script.sh || git checkout -- script.sh

Récupération pas à pas (playbooks)

Adaptez ces scénarios aux incidents les plus fréquents.

1) Commande introuvable ou mauvais binaire

Symptômes : command not found ou une version inattendue s’exécute.

Vérifications

type -a tool
printf '%s\n' "$PATH" | tr ':' '\n'
hash -r

Correctifs

  • Installer ou ajuster PATH dans le script : export PATH=/opt/tool/bin:$PATH.
  • Utiliser des chemins absolus pour les binaires critiques.
  • En conteneur, placer la dépendance dans l’image ou l’installer au démarrage.

2) Crash de variable non liée

Symptômes : unbound variable avec set -u.

Vérifications

set -u
: "${NAME:?NAME is required}"

Correctifs

  • Fournir des valeurs par défaut ou des erreurs explicites :
  NAME="${NAME:-guest}"
  API_URL="${API_URL:?required}"

3) Échec masqué par un pipeline

Symptômes : la dernière commande réussit mais une étape amont a échoué.

Vérification et correctif

set -o pipefail
foo | bar | baz
printf '%s\n' "${PIPESTATUS[@]}"

Si un retour non-zéro de grep sans correspondance est acceptable, ajoutez || true.

4) Problème de permission ou de shebang

Symptômes : Permission denied ou le script tourne sous sh au lieu de Bash.

Vérifications et correctifs

chmod +x script.sh
sed -n '1p' script.sh   # attendre #!/usr/bin/env bash
bash -n script.sh

5) Fins de ligne CRLF qui cassent l’exécution

Symptômes : apparition de ^M ou scripts qui échouent dans des conteneurs Linux.

Correctif

file script.sh
dos2unix script.sh || sed -i 's/\r$//' script.sh

6) Bug de guillemets et expansion inattendue

Symptômes : noms de fichiers avec espaces qui cassent les boucles ou des cibles mal résolues.

Patron de correctif

# Toujours citer les expansions
rm -- "$file"
# find + xargs en toute sécurité
find . -type f -name '*.log' -print0 | xargs -0 rm -f --

7) Différences cron vs interactif

Symptômes : un script réussit en shell, échoue sous cron ou un job runner.

Vérifications

( env | sort ) > interactive.env
( env -i bash -lc 'env' | sort ) > isolated.env
diff -u interactive.env isolated.env || true

Correctifs

  • Définir PATH explicitement dans le script.
  • Utiliser des chemins absolus pour les fichiers et binaires.
  • Sourcer un profil connu si requis, ou exporter les variables nécessaires dans la crontab.

Spécificités Docker et Docker Compose

  • Reproduire à l’intérieur de la même image
  docker run --rm -it -v "$PWD":/work -w /work myimg bash -lc './script.sh'
  docker exec -it mycontainer bash -lc 'type -a tool && ./script.sh'
  • Vérifier propriétaire et permissions après des bind mounts.
  • Normaliser les fins de ligne sur l’hôte avant de builder l’image.
  • Shell sur un service Compose
  docker compose run --rm svc bash -lc 'set -euxo pipefail; ./script.sh'

Spécificités Kubernetes (Pods, Ingress, Secrets)

  • Exec dans le conteneur avec le bon shell
  kubectl exec -it deploy/app -c app -- bash -lc 'type -a bash || cat /etc/os-release'
  • Logs et redémarrages
  kubectl logs deploy/app -c app --timestamps --previous
  • Config et secrets (sans les exposer)
  ls -l /etc/config /etc/secret
  stat /etc/secret/*
  set +x; KEY="${API_KEY:?missing}"; set -x
  • Vérifications réseau utiles à Ingress et services
  curl -sv http://svc.namespace.svc.cluster.local:8080/health || true
  getent hosts example.com
  nc -zv example.com 443 || true

Plan pilote local

Gardez votre première implémentation petite, mesurable et simple à inspecter localement.

  1. Choisir 3 échecs fréquents
  • Exemple : variable non liée, lignes CRLF et échec masqué de pipeline.
  1. Créer des repros minimaux
# repro-unbound.sh
set -u; echo "Hello $NAME"

# repro-crlf.sh (volontairement CRLF)
printf 'echo win\r\n' > repro-crlf.sh

# repro-pipe.sh
false | grep x
  1. Ajouter un wrapper de trace et logs
run_traced() {
  exec {XTRACE_FD}>trace.log
  export BASH_XTRACEFD=$XTRACE_FD
  export PS4='+ ${EPOCHREALTIME} ${BASH_SOURCE}:${LINENO}: '
  set -x; "$@"; ec=$?; set +x
  exec {XTRACE_FD}>&-
  return "$ec"
}
run_traced bash repro-unbound.sh || true
  1. Mesurer le temps de correction
  • Mesurez le temps nécessaire pour identifier et corriger avant/après wrapper et check-list.
  • Un timer simple :
  time bash repro-unbound.sh
  1. Étendre aux conteneurs et aux clusters
  • Une fois le pilote local stable, reproduisez dans votre image Docker et dans un pod Kubernetes, puis appliquez les mêmes vérifications et wrappers.

Conclusion

Le dépannage Bash s’accélère et devient fiable quand vous suivez un workflow clair, capturez les bons logs, utilisez des commandes de récupération sûres et appliquez des playbooks éprouvés pour les échecs courants. Démarrez petit en local, mesurez l’impact, puis étendez les mêmes schémas à Docker, Docker Compose et Kubernetes (Ingress et Secrets compris). Enrichissez progressivement vos exemples et snippets pour rendre les incidents futurs prévisibles et à faible risque.

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO