Je commence à utiliser rsync
et j'essaie de l'utiliser pour garder deux dossiers synchronisés sur le système local. J'ai un dossier source, dont le contenu change au fil du temps (certains fichiers sont ajoutés, certaines modifications et d'autres supprimées) et un dossier cible que je veux presque faire un miroir de la source. Donc ce que j'ai essayé utilisait rsync comme ceci:
rsync -a --delete "${source_dir}" "${target_dir}";
Cela permet de garder le contenu de la cible exactement identique au contenu de la source. Cependant, j'aimerais pouvoir ajouter des fichiers à la cible et non à la source, mais je ne veux pas qu'ils soient supprimés à chaque fois que je fais rsync. D'autre part, les fichiers qui étaient synchronisés et ensuite supprimés dans le source doivent toujours l'être.
Y a-t-il un moyen de le faire sans avoir à modifier la commande pour chaque fichier que je veux exclure?
Mise à jour: Je devrais mentionner que je ne suis pas limité à rsync. Si un autre programme fait le travail, c'est bien aussi. J'ai juste essayé de résoudre cela en utilisant rsync.
rsync
dispose d'une option appelée --exclude-from
qui permet de créer un fichier contenant une liste des fichiers que vous souhaitez exclure. Vous pouvez mettre à jour ce fichier chaque fois que vous souhaitez ajouter une nouvelle exclusion ou en supprimer une ancienne.
Si vous créez le fichier d'exclusion sous /home/user/rsync_exclude
, la nouvelle commande serait:
rsync -a --delete --exclude-from="/home/user/rsync_exclude" "${source_dir}" "${target_dir}"
Lors de la création du fichier de liste d'exclusion, vous devez placer chaque règle d'exclusion sur une ligne distincte. Les exclusions sont relatives à votre répertoire source. Si votre fichier /home/user/rsync_exclude
contient les options suivantes:
secret_file
first_dir/subdir/*
second_dir/common_name.*
secret_file
dans votre répertoire source sera exclu.${source_dir}/first_dir/subdir
seront exclus, mais une version vide de subdir
sera synchronisée.${source_dir}/second_dir
avec le préfixe common_name.
seront ignorés. Donc, common_name.txt
, common_name.jpg
etc.Puisque vous avez mentionné: , je ne suis pas limité à rsync:
Ci-dessous un script qui fait exactement ce que vous décrivez.
Le script peut être exécuté en mode verbose (à définir dans le script), qui affichera la progression de la sauvegarde (mise en miroir). Inutile de dire que cela peut également être utilisé pour enregistrer les sauvegardes:
Option détaillée
.recentfiles
.currentfiles
..recentfiles
(répertoriant la situation sur la sauvegarde précédente) est comparé à .currentfiles
. Seuls les fichiers de .recentfiles
qui ne figurent pas dans .currentfiles
sont évidemment supprimés de la source, et sera retiré de la cible..currentfiles
temporaire est renommé en .recentfiles
pour servir le prochain cycle de sauvegarde, etc.#!/usr/bin/env python3
import os
import sys
import shutil
dr1 = sys.argv[1]; dr2 = sys.argv[2]
# --- choose verbose (or not)
verbose = True
# ---
recentfiles = os.path.join(dr2, ".recentfiles")
currentfiles = os.path.join(dr2, ".currentfiles")
if verbose:
print("Counting items in source...")
file_count = sum([len(files)+len(d) for r, d, files in os.walk(dr1)])
print(file_count, "items in source")
print("Reading directory & file structure...")
done = 0; chunk = int(file_count/5); full = chunk*5
def show_percentage(done):
if done % chunk == 0:
print(str(int(done/full*100))+"%...", end = " ")
for root, dirs, files in os.walk(dr1):
for dr in dirs:
if verbose:
if done == 0:
print("Updating mirror...")
done = done + 1
show_percentage(done)
target = os.path.join(root, dr).replace(dr1, dr2)
source = os.path.join(root, dr)
open(currentfiles, "a+").write(target+"\n")
if not os.path.exists(target):
shutil.copytree(source, target)
for f in files:
if verbose:
done = done + 1
show_percentage(done)
target = os.path.join(root, f).replace(dr1, dr2)
source = os.path.join(root, f)
open(currentfiles, "a+").write(target+"\n")
sourcedit = os.path.getmtime(source)
try:
if os.path.getmtime(source) > os.path.getmtime(target):
shutil.copy(source, target)
except FileNotFoundError:
shutil.copy(source, target)
if verbose:
print("\nChecking for deleted files in source...")
if os.path.exists(recentfiles):
recent = [f.strip() for f in open(recentfiles).readlines()]
current = [f.strip() for f in open(currentfiles).readlines()]
remove = set([f for f in recent if not f in current])
for f in remove:
try:
os.remove(f)
except IsADirectoryError:
shutil.rmtree(f)
except FileNotFoundError:
pass
if verbose:
print("Removed:", f.split("/")[-1])
if verbose:
print("Done.")
shutil.move(currentfiles, recentfiles)
backup_special.py
Changez, si vous le souhaitez, l’option verbeuse dans l’en-tête du script:
# --- choose verbose (or not)
verbose = True
# ---
Exécutez-le avec les arguments source et target:
python3 /path/to/backup_special.py <source_directory> <target_directory>
J'ai testé le script sur un répertoire de 10 Go contenant environ 40 000 fichiers et répertoires sur mon lecteur réseau (NAS). La sauvegarde a été effectuée pratiquement en même temps que rsync.
La mise à jour de l'ensemble du répertoire n'a pris que quelques secondes de plus que rsync, sur 40 000 fichiers, ce qui est inacceptable et sans surprise, car le script doit comparer le contenu à la dernière sauvegarde effectuée. .