自从您提到:我不仅限于rsync:
维护镜像的脚本,允许向目标添加额外的文件
脚本下面的内容完全符合您的描述。
该脚本可以在详细模式下运行(在脚本中进行设置),该模式将输出备份的进度(镜像)。无需说这也可以用来记录备份:
详细选项
这个概念
1.首次备份时,脚本:
- 在目标目录中创建一个文件,列出所有文件和目录;
.recentfiles
- 创建目标目录中所有文件和目录的精确副本(镜像)
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
# ---
使用source和target作为参数运行它:
python3 /path/to/backup_special.py <source_directory> <target_directory>
速度
我在10 GB目录中测试了该脚本,并在网络驱动器(NAS)上存储了约40.000个文件和目录,它几乎与rsync同时进行了备份。
在40.000个文件上,更新整个目录只花了rsync几秒钟的时间,这对于imo来说是可以接受的,也就不足为奇了,因为脚本需要将内容与上次进行的备份进行比较。