あなたが言及したので:私はrsyncに限定されていません:
ミラーを維持するスクリプト。ターゲットにファイルを追加できます。
あなたが説明したとおりのことを行うスクリプトの下。
スクリプトは冗長モード(スクリプトで設定する)で実行でき、バックアップ(ミラーリング)の進行状況を出力します。これはバックアップのログにも使用できると言う必要はありません。
冗長オプション
コンセプト
1.最初のバックアップで、スクリプトは:
- すべてのファイルとディレクトリがリストされているファイルを(ターゲットディレクトリに)作成します。
.recentfiles
- ターゲットディレクトリ内のすべてのファイルとディレクトリの正確なコピー(ミラー)を作成します
2.次回以降のバックアップ
- スクリプトは、ファイルのディレクトリ構造と変更日を比較します。ソース内の新しいファイルとディレクトリがミラーにコピーされます。同時に、2番目の(一時的な)ファイルが作成され、ソースディレクトリ内の現在のファイルとディレクトリが一覧表示されます。
.currentfiles
。
- 続いて、
.recentfiles
(以前のバックアップの状況をリストする)がと比較され.currentfiles
ます。のみのファイル.recentfiles
ではありませんこれは.currentfiles
明らかに、ソースから削除され、ターゲットから削除されます。
- ターゲットフォルダーに手動で追加したファイルは、スクリプトによって「見えない」状態になり、そのまま残されます。
- 最後に、次のバックアップサイクルを提供する
.currentfiles
ため.recentfiles
に一時ファイルの名前が変更されます。
スクリプト
#!/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
スクリプトの先頭にある-必要に応じて-詳細オプションを変更します。
# --- choose verbose (or not)
verbose = True
# ---
引数としてソースとターゲットを指定して実行します。
python3 /path/to/backup_special.py <source_directory> <target_directory>
速度
ネットワークドライブ(NAS)に約40.000個のファイルとディレクトリがある10 GBのディレクトリでスクリプトをテストしました。rsyncとほぼ同じ時間でバックアップが作成されました。
スクリプトが最後に作成されたバックアップと内容を比較する必要があるため、ディレクトリ全体の更新はrsyncよりも数秒だけ長く、40.000ファイルで完了しました。