Retour au cours

projet : un script de sauvegarde intelligent

Objectif du Projet

Mettre en pratique toutes les compétences de scripting Bash acquises pour créer un outil en ligne de commande flexible, robuste et réutilisable pour effectuer des sauvegardes de dossiers.

Le Scénario

Vous avez plusieurs dossiers importants sur votre système (ex: /var/www, /home/alice/documents, /etc/nginx), et vous voulez un seul script capable de sauvegarder n’importe lequel d’entre eux dans une archive compressée, horodatée, et qui gère automatiquement la suppression des plus anciennes sauvegardes.

Fonctionnalités attendues

  1. Le script doit prendre le dossier source et le dossier de destination en arguments.
  2. Il doit créer une archive .tar.gz avec un nom contenant la date et l’heure.
  3. Il doit mettre en place une “rotation” : ne conserver, par exemple, que les 7 dernières sauvegardes.
  4. Il doit être robuste : afficher une aide, valider ses arguments, et s’arrêter en cas d’erreur.

Le Script Complet

Ce script est une synthèse de tout ce que nous avons vu : set -e, fonctions, getopts pour les arguments, date pour le nommage, tar pour l’archivage, et find pour le nettoyage.

#!/usr/bin/env bash

# Mode strict
set -euo pipefail

# --- Documentation et Constantes ---
readonly SCRIPT_NAME="$(basename "$0")"

# --- Fonctions ---

# Affiche un message d'erreur sur stderr et quitte
die() {
  echo >&2 "[ERREUR] $@"
  exit 1
}

# Affiche le message d'aide
usage() {
  echo "Usage: $SCRIPT_NAME -s <dossier_source> -d <dossier_destination> [-k <jours>]"
  echo "Crée une sauvegarde compressée d'un dossier avec rotation."
  echo ""
  echo "Options:"
  echo "  -s <source>   Dossier à sauvegarder (obligatoire)."
  echo "  -d <dest>     Dossier où stocker les sauvegardes (obligatoire)."
  echo "  -k <jours>    Nombre de jours de rétention (optionnel, 7 par défaut)."
  echo "  -h            Affiche cette aide."
  exit 0
}

# --- Fonction Principale ---
main() {
  local SOURCE_DIR=""
  local DEST_DIR=""
  local RETENTION_DAYS=7

  while getopts ":hs:d:k:" opt; do
    case "$opt" in
      h) usage ;;
      s) SOURCE_DIR="$OPTARG" ;;
      d) DEST_DIR="$OPTARG" ;;
      k) RETENTION_DAYS="$OPTARG" ;;
      \?|:) die "Option invalide ou argument manquant. Utilisez -h pour l'aide." ;;
    esac
  done
  shift $((OPTIND - 1))

  # --- Validation ---
  if [[ -z "$SOURCE_DIR" || -z "$DEST_DIR" ]]; then
    usage
  fi
  if [[ ! -d "$SOURCE_DIR" ]]; then
    die "Le dossier source '$SOURCE_DIR' n'existe pas."
  fi
  # On crée le dossier de destination s'il n'existe pas
  mkdir -p "$DEST_DIR"

  # --- Logique Principale ---
  local DATE_TAG
  DATE_TAG=$(date +"%Y-%m-%d_%H%M%S")
  local BASENAME_SOURCE
  BASENAME_SOURCE=$(basename "$SOURCE_DIR")
  local ARCHIVE_NAME="backup-${BASENAME_SOURCE}-${DATE_TAG}.tar.gz"
  local DEST_FILE="${DEST_DIR}/${ARCHIVE_NAME}"

  echo "INFO: Création de la sauvegarde : '$DEST_FILE'..."
  
  tar -czf "$DEST_FILE" -C "$(dirname "$SOURCE_DIR")" "$BASENAME_SOURCE"

  echo "INFO: Sauvegarde terminée avec succès."

  # --- Rotation des sauvegardes ---
  echo "INFO: Application de la politique de rétention (${RETENTION_DAYS} jours)..."
  # Le '|| true' est une sécurité si find ne trouve aucun fichier, pour ne pas faire échouer le script
  find "$DEST_DIR" -type f -name "backup-${BASENAME_SOURCE}-*.tar.gz" -mtime "+$RETENTION_DAYS" -print -delete || true
  
  echo "INFO: Rotation terminée."
}

# --- Point d'entrée ---
main "$@"

Comment l’utiliser et l’automatiser ?

  1. Sauvegardez ce script (ex: dans /usr/local/bin/mon_backup.sh) et rendez-le exécutable (chmod +x).
  2. Lancez-le manuellement pour tester :
    sudo /usr/local/bin/mon_backup.sh -s /var/log -d /mnt/backups -k 30
  3. Automatisez-le avec cron :
    • Ouvrez la crontab de root (sudo crontab -e).
    • Ajoutez une ligne pour l’exécuter tous les jours à 2h du matin.
    0 2 * * * /usr/local/bin/mon_backup.sh -s /var/www -d /mnt/backups > /var/log/backup.log 2>&1

Exercices et améliorations

  1. Mise en place :

    • Enregistrez le script sur votre machine.
    • Créez un dossier source_test avec quelques fichiers et un dossier dest_test.
    • Exécutez le script pour sauvegarder source_test dans dest_test. Vérifiez que l’archive est créée.
  2. Ajouter des logs :

    • Modifiez le script pour qu’il accepte une option -l <fichier_log>.
    • S’il reçoit cette option, tous les messages echo doivent être redirigés à la fois vers le terminal et vers le fichier de log. (Indice : echo "message" | tee -a "$LOG_FILE").
  3. Vérifier l’espace disque :

    • Avant de lancer tar, ajoutez une vérification avec df pour vous assurer qu’il y a suffisamment d’espace disque disponible dans la destination.
    • Si ce n’est pas le cas, appelez la fonction die avec un message d’erreur clair.