sauvegarde_rsync.sh
Note de lecture générée automatiquement
Le vrai fichier est
scripts/sauvegarde/sauvegarde_rsync.sh(Obsidian n’affiche pas les scripts eux-mêmes). Ne modifie pas cette note : modifie le script, puis relancepython3 generer_vues_obsidian.pydans le dossierscripts.
- À quoi il sert : Sauvegardes incrémentales datées + rotation
- Lancer (dans le dossier
scripts/sauvegarde/) :./sauvegarde_rsync.sh <source> <destination> [nb_a_garder] - Fiche : ST02 - Stratégies de sauvegarde
- Retour : 00 - Tous les scripts
Code
#!/usr/bin/env bash
# =============================================================================
# sauvegarde_rsync.sh — Sauvegarde incrémentale "par instantanés" avec rsync
#
# Chaque exécution crée un dossier daté (AAAA-MM-JJ_HHhMM). Les fichiers qui
# n'ont pas changé ne sont PAS recopiés : ce sont des liens physiques vers la
# sauvegarde précédente (--link-dest). Chaque dossier paraît donc complet
# (restauration facile) mais ne prend que la place des fichiers modifiés.
# Les N plus anciens instantanés sont supprimés (rotation).
#
# Usage : ./sauvegarde_rsync.sh <dossier_source> <dossier_destination> [nb_a_garder]
# Exemple : ./sauvegarde_rsync.sh "$HOME/obsidian/truc non trier" /media/disque_usb/vault 7
# Auto : crontab -e puis 0 20 * * * /chemin/sauvegarde_rsync.sh "/src" "/dest" 7
# =============================================================================
set -euo pipefail
source_a_sauver="${1:?Usage : $0 <source> <destination> [nb_a_garder]}"
destination="${2:?Destination manquante}"
nb_a_garder="${3:-7}"
-d "$source_a_sauver" || { echo "Source introuvable : $source_a_sauver" >&2; exit 1; }
mkdir -p "$destination"
horodatage="$(date +%Y-%m-%d_%Hh%M)"
nouvel_instantane="$destination/$horodatage"
dernier_instantane="$(find "$destination" -mindepth 1 -maxdepth 1 -type d -name '20*' | sort | tail -n 1)"
options_rsync=(-a --delete --human-readable --info=stats1)
if -n "$dernier_instantane"; then
options_rsync+=(--link-dest="$dernier_instantane")
echo "Incrémentale par rapport à : $dernier_instantane"
else
echo "Première sauvegarde : copie complète."
fi
# Le "/" final sur la source = copier le CONTENU du dossier
rsync "${options_rsync[@]}" "${source_a_sauver%/}/" "$nouvel_instantane/"
# Rotation : on supprime les plus vieux au-delà de nb_a_garder
mapfile -t instantanes < <(find "$destination" -mindepth 1 -maxdepth 1 -type d -name '20*' | sort)
nb_a_supprimer=$(( ${#instantanes[@]} - nb_a_garder ))
if (( nb_a_supprimer > 0 )); then
for ancien in "${instantanes[@]:0:nb_a_supprimer}"; do
echo "Rotation : suppression de $ancien"
rm -rf -- "$ancien"
done
fi
echo "Sauvegarde terminée : $nouvel_instantane"
du -sh "$destination"/20* 2>/dev/null | tail -n "$nb_a_garder"