rsync:同步文件夹,但在目标中保留额外的文件

jkr*_*ski 11 sync command-line backup rsync directory

我开始rsync使用它并尝试使用它来保持本地系统上的两个文件夹同步。我有一个源文件夹,其内容会随着时间的推移而发生变化(一些文件被添加,一些更改和一些删除)和一个我想几乎成为源镜像的目标文件夹。所以我尝试过像这样使用 rsync:

rsync -a --delete "${source_dir}" "${target_dir}";

这确实使目标的内容与源的内容完全相同。但是,我希望能够将一些文件添加到目标而不是源,但我不希望每次执行 rsync 时都将它们删除。另一方面,以前同步然后在源中被删除的文件仍然应该被删除。

有没有办法做到这一点,而不必为我想要排除的每个文件更改命令?

更新:我应该提到我不仅限于 rsync。如果另一个程序完成了工作,那也很好。我只是尝试使用 rsync 来解决这个问题。

Arr*_*cal 9

rsync有一个名为--exclude-fromoption 的选项,它允许您创建一个文件,其中包含要排除的任何文件的列表。您可以在想要添加新排除项或删除旧排除项时更新此文件。

如果您在/home/user/rsync_exclude新命令中创建排除文件将是:

rsync -a --delete --exclude-from="/home/user/rsync_exclude" "${source_dir}" "${target_dir}"
Run Code Online (Sandbox Code Playgroud)

创建排除列表文件时,您应该将每个排除规则放在单独的行上。排除项与您的源目录相关。如果您的/home/user/rsync_exclude文件包含以下选项:

secret_file
first_dir/subdir/*
second_dir/common_name.*
Run Code Online (Sandbox Code Playgroud)
  • secret_file将排除在源目录中调用的任何文件或目录。
  • 中的任何文件都${source_dir}/first_dir/subdir将被排除,但subdir将同步一个空版本。
  • 任何${source_dir}/second_dir带有前缀的文件都common_name.将被忽略。所以common_name.txtcommon_name.jpg等等。


Jac*_*ijm 6

既然你提到:我不仅限于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)
Run Code Online (Sandbox Code Playgroud)

如何使用

  1. 将脚本复制到一个空文件中,另存为 backup_special.py
  2. 更改 - 如果需要 - 脚本头部的详细选项:

    # --- choose verbose (or not)
    verbose = True
    # ---
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用源和目标作为参数运行它:

     python3 /path/to/backup_special.py <source_directory> <target_directory>
    
    Run Code Online (Sandbox Code Playgroud)

速度

我在一个 10 GB 的目录上测试了脚本,在我的网络驱动器 (NAS) 上有大约 40.000 个文件和目录,它与 rsync 几乎同时进行了备份。

在 40.000 个文件上更新整个目录只比 rsync 多花几秒钟,这是可以接受的,这并不奇怪,因为脚本需要将内容与上次备份的内容进行比较。