Da Sie erwähnt haben: Ich bin nicht auf rsync beschränkt:
Skript zum Verwalten des Spiegels, mit dem zusätzliche Dateien zum Ziel hinzugefügt werden können
Unten ein Skript, das genau das tut, was Sie beschreiben.
Das Skript kann im ausführlichen Modus ausgeführt werden (der im Skript festgelegt wird), der den Fortschritt der Sicherung ausgibt (Spiegelung). Sie müssen nicht sagen, dass dies auch zum Protokollieren der Sicherungen verwendet werden kann:
Ausführliche Option
Das Konzept
1. Bei der ersten Sicherung das Skript:
- erstellt eine Datei (im Zielverzeichnis), in der alle Dateien und Verzeichnisse aufgelistet sind;
.recentfiles
- Erstellt eine exakte Kopie (Spiegelung) aller Dateien und Verzeichnisse im Zielverzeichnis
2. Beim nächsten und so weiter Backup
- Das Skript vergleicht die Verzeichnisstruktur und das Änderungsdatum (die Änderungsdaten) der Dateien. Neue Dateien und Verzeichnisse in der Quelle werden in den Spiegel kopiert. Gleichzeitig wird eine zweite (temporäre) Datei erstellt, in der die aktuellen Dateien und Verzeichnisse im Quellverzeichnis aufgelistet sind.
.currentfiles
.
- Anschließend wird
.recentfiles
(Auflistung der Situation bei der vorherigen Sicherung) mit verglichen .currentfiles
. Nur Dateien, aus .recentfiles
denen nicht vorhanden ist, .currentfiles
werden offensichtlich aus der Quelle entfernt und vom Ziel entfernt.
- Dateien, die Sie manuell zum Zielordner hinzugefügt haben, werden vom Skript ohnehin nicht "gesehen" und bleiben in Ruhe.
- Schließlich wird die temporäre
.currentfiles
Datei umbenannt, .recentfiles
um den nächsten Sicherungszyklus usw. bereitzustellen.
Das Skript
#!/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)
Wie benutzt man
- Kopieren Sie das Skript in eine leere Datei und speichern Sie es unter
backup_special.py
Ändern Sie - wenn Sie möchten - die ausführliche Option im Kopf des Skripts:
# --- choose verbose (or not)
verbose = True
# ---
Führen Sie es mit Quelle und Ziel als Argumente aus:
python3 /path/to/backup_special.py <source_directory> <target_directory>
Geschwindigkeit
Ich habe das Skript in einem 10-GB-Verzeichnis mit etwa 40.000 Dateien und Verzeichnissen auf meinem Netzlaufwerk (NAS) getestet. Die Sicherung wurde fast zur gleichen Zeit wie bei rsync durchgeführt.
Das Aktualisieren des gesamten Verzeichnisses dauerte bei 40.000 Dateien nur wenige Sekunden länger als bei rsync. Dies ist nicht akzeptabel und keine Überraschung, da das Skript den Inhalt mit dem zuletzt erstellten Backup vergleichen muss.