rsync: 폴더를 동기화하지만 대상에 추가 파일을 보관합니다.

rsync: 폴더를 동기화하지만 대상에 추가 파일을 보관합니다.

저는 로컬 시스템의 두 폴더를 동기화하기 위해 시작 rsync하고 이를 사용하려고 했습니다. 시간이 지남에 따라 내용이 변경되는 소스 폴더(일부 파일은 추가되고 일부는 변경되고 일부는 삭제됨)와 거의 소스의 미러 역할을 하려는 대상 폴더가 있습니다. 그래서 제가 시도한 것은 다음과 같이 rsync를 사용하는 것이었습니다.

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

이렇게 하면 대상의 내용이 소스의 내용과 정확히 동일하게 유지됩니다. 그러나 일부 파일을 소스가 아닌 대상에 추가할 수 있기를 원하지만 rsync를 수행할 때마다 해당 파일이 삭제되는 것을 원하지 않습니다. 반면, 동기화된 후 소스에서 삭제된 파일은 계속 삭제해야 합니다.

제외하려는 모든 파일에 대해 명령을 변경하지 않고도 이 작업을 수행할 수 있는 방법이 있습니까?

업데이트: 나는 rsync에만 국한되지 않는다는 점을 언급하고 싶습니다. 다른 프로그램이 작업을 완료하면 그것도 괜찮습니다. 방금 rsync를 사용하여 이 문제를 해결하려고 했습니다.

답변1

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

답변2

당신이 언급한 이후:나는 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)

사용하는 방법

  1. 스크립트를 빈 파일에 복사하고 다른 이름으로 저장하세요.backup_special.py
  2. 원하는 경우 스크립트 헤드의 자세한 정보 표시 옵션을 변경하세요.

    # --- choose verbose (or not)
    verbose = True
    # ---
    
  3. 소스 및 대상을 인수로 사용하여 실행하십시오.

     python3 /path/to/backup_special.py <source_directory> <target_directory>
    

속도

내 네트워크 드라이브(NAS)에 약 40,000개의 파일과 디렉토리가 있는 10GB 디렉토리에서 스크립트를 테스트했는데, rsync와 거의 동시에 백업이 이루어졌습니다.

업데이트 중전체 디렉터리는 40,000개 파일에서 rsync보다 몇 초 더 걸렸습니다. 이는 스크립트가 마지막으로 만든 백업과 콘텐츠를 비교해야 하기 때문에 수용 가능하고 놀라운 일이 아닙니다.

관련 정보