rsync
を使い始めて、ローカルシステム上の2つのフォルダーを同期するために使用しようとしました。内容が時間とともに変化するソースフォルダー(一部のファイルが追加され、一部の変更が行われ、一部が削除されます)と、ソースのほぼミラーにしたいターゲットフォルダーがあります。だから私はこのようなrsyncを使用してみました:
rsync -a --delete "${source_dir}" "${target_dir}";
これにより、ターゲットのコンテンツはソースのコンテンツとまったく同じになります。ただし、ソースではなくターゲットにいくつかのファイルを追加できるようにしたいのですが、rsyncを実行するたびにファイルを削除したくありません。一方、以前は同期されていたがソースで削除されたファイルは削除する必要があります。
除外するすべてのファイルのコマンドを変更せずにこれを行う方法はありますか?
更新:rsyncに限定されないことに言及する必要があります。別のプログラムが仕事を終わらせたとしても、それで問題ありません。 rsyncを使用してこれを解決しようとしました。
rsync
には--exclude-from
オプションと呼ばれるオプションがあり、除外したいファイルのリストを含むファイルを作成できます。新しい除外を追加したり、古い除外を削除したりする場合は、いつでもこのファイルを更新できます。
/home/user/rsync_exclude
に除外ファイルを作成すると、新しいコマンドは次のようになります。
rsync -a --delete --exclude-from="/home/user/rsync_exclude" "${source_dir}" "${target_dir}"
除外リストファイルを作成するときは、各除外ルールを別々の行に配置する必要があります。除外はソースディレクトリに関連しています。 /home/user/rsync_exclude
ファイルに次のオプションが含まれている場合:
secret_file
first_dir/subdir/*
second_dir/common_name.*
secret_file
というファイルまたはディレクトリは除外されます。${source_dir}/first_dir/subdir
のファイルはすべて除外されますが、subdir
の空のバージョンは同期されます。${source_dir}/second_dir
のプレフィックスがcommon_name.
であるファイルはすべて無視されます。 common_name.txt
、common_name.jpg
など.あなたが言及したので:私はrsync:に限定されません
以下に、記述したとおりのことを行うスクリプトを示します。
スクリプトはverboseモード(スクリプトで設定される)で実行でき、バックアップの進行状況(ミラーリング)を出力します。これをバックアップのログに使用できると言う必要はありません。
詳細オプション
.recentfiles
.currentfiles
。.recentfiles
(以前のバックアップの状況をリスト)が.currentfiles
と比較されます。 Only.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とほぼ同じ時間でバックアップを作成しました。
更新40.000ファイルでは、ディレクトリ全体がrsyncよりも数秒しかかかりませんでしたが、スクリプトはコンテンツを最後に作成したバックアップと比較する必要があるため、これは受け入れられ、驚くことではありません。