Aller au contenu

Bash : bonnes pratiques

Quelques habitudes évitent la plupart des problèmes d’un script, surtout quand il tourne sans surveillance (cron, déploiement). Les exemples utilisent des noms génériques.

#!/usr/bin/env bash
set -euo pipefail
# --- Configuration ---
DOSSIER="${1:?Usage: $0 <dossier>}"
# --- Fonctions ---
log() { echo "$(date '+%F %T') $*"; }
# --- Programme principal ---
log "Début"
# ...
log "Fin"
Option Effet
-e Le script s’arrête dès qu’une commande échoue
-u Utiliser une variable non définie est une erreur (évite rm -rf "$DOSSIER/" avec DOSSIER vide)
-o pipefail Un pipe échoue si une de ses commandes échoue, pas seulement la dernière

Limites à connaître :

Fenêtre de terminal
# grep renvoie 1 quand rien ne correspond : avec set -e, le script s'arrêterait
nb="$(grep -c "motif" fichier || true)" # « || true » : ignorer l'échec
# Une commande dans un if ou avec && / || ne déclenche pas set -e
if grep -q "motif" fichier; then echo "trouvé"; fi

Autre piège avec pipefail : head ferme le pipe dès qu’il a assez de lignes, et la commande en amont reçoit alors le signal SIGPIPE (code 141), ce qui fait échouer le pipe et arrêter le script :

Fenêtre de terminal
sort -rn grosse-liste.txt | head -n 3 # peut échouer (code 141) avec set -e -o pipefail
sort -rn grosse-liste.txt | awk 'NR <= 3' # awk lit tout : pas de SIGPIPE
Fenêtre de terminal
cp "$source" "$destination" # correct, même avec des espaces
rm -rf "${DOSSIER:?}/"* # « :? » refuse une variable vide
Fenêtre de terminal
# Être root si nécessaire
if [[ $EUID -ne 0 ]]; then
echo "Ce script doit être lancé avec sudo" >&2
exit 1
fi
# Commande disponible ?
command -v rsync >/dev/null || { echo "rsync est requis" >&2; exit 1; }
# Fichier ou dossier présent ?
[[ -d "$DOSSIER" ]] || { echo "Dossier introuvable : $DOSSIER" >&2; exit 1; }

trap exécute une commande quand le script se termine, même en cas d’erreur ou d’interruption (Ctrl+c) :

Fenêtre de terminal
tmp="$(mktemp -d)" # dossier temporaire unique
trap 'rm -rf "$tmp"' EXIT # supprimé à la fin, quoi qu'il arrive
echo "données" > "$tmp/fichier"

mktemp crée un nom de fichier ou de dossier unique : ne pas utiliser un nom fixe dans /tmp (risque de collision et de sécurité).

Fenêtre de terminal
exec 9> /tmp/mon-script.lock
flock -n 9 || { echo "Une autre instance est en cours" >&2; exit 1; }
Fenêtre de terminal
LOG="/var/log/mon-script.log"
exec >> "$LOG" 2>&1 # tout ce qui suit est écrit dans le journal
echo "$(date '+%F %T') Démarrage"

Pour une sortie à la fois à l’écran et dans un fichier : ./script.sh 2>&1 | tee -a script.log.

Un script idempotent peut être relancé sans dommage :

Fenêtre de terminal
mkdir -p /srv/donnees # n'échoue pas si le dossier existe
grep -qxF "ligne" fichier || echo "ligne" >> fichier # ajoute la ligne seulement si absente
ln -sfn /srv/v2 /srv/courant # remplace le lien s'il existe
Fenêtre de terminal
sudo apt install shellcheck
shellcheck script.sh # détecte guillemets manquants, erreurs courantes et pièges
bash -n script.sh # vérifie seulement la syntaxe

ShellCheck est l’outil le plus utile pour progresser : chaque avertissement est expliqué (SC2086 : variable sans guillemets, par exemple).

Cron s’exécute avec un environnement minimal : ni les variables ni le PATH habituels.

Fenêtre de terminal
crontab -e
# Sauvegarde tous les jours à 3 h, journal des erreurs conservé
0 3 * * * /usr/local/bin/sauvegarde.sh >> /var/log/sauvegarde.log 2>&1
  • Utiliser des chemins absolus pour les commandes et les fichiers.
  • Rediriger la sortie vers un journal (sans quoi elle part par courrier local).
  • Tester d’abord le script à la main, avec env -i bash script.sh pour simuler un environnement vide.
  • Un nom de script explicite (sauvegarde-dossier.sh), une brève description en commentaire et un message d’usage.
  • Les valeurs modifiables en haut du script, en majuscules.
  • Des fonctions courtes ; local pour leurs variables.
  • Un script de plus de quelques centaines de lignes, ou avec des structures de données complexes : envisager un langage plus adapté (Python).

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »
  • ShellCheck : shellcheck.net
  • Manuel : man bash, section « SHELL BUILTIN COMMANDS »