rsync : 폴더를 동기화하지만 추가 파일을 대상에 유지


10

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

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

이렇게하면 대상의 내용이 소스의 내용과 정확히 동일하게 유지됩니다. 그러나 소스가 아닌 대상에 일부 파일을 추가하고 싶지만 rsync를 수행 할 때마다 파일을 삭제하고 싶지 않습니다. 반면, 동기화 된 다음 소스에서 삭제 된 파일은 여전히 ​​삭제해야합니다.

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

업데이트 : 나는 rsync로 제한되지 않는다는 것을 언급해야합니다. 다른 프로그램이 작업을 수행하면 괜찮습니다. 방금 rsync를 사용 하여이 문제를 해결하려고했습니다.


안녕 @AszunesHeart, 그냥 궁금하지만 답변을 테스트 했습니까?
Jacob Vlijm

--delete 옵션을 사용해 보셨습니까? 이것은 Robocopy의 / MIR 옵션과 같습니다.
SDsolar

답변:


9

rsync--exclude-from제외 할 파일 목록이 포함 된 파일을 만들 수 있는 option 옵션이 있습니다. 새 제외를 추가하거나 이전 제외를 제거 할 때마다이 파일을 업데이트 할 수 있습니다.

/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_exclude-file에 해당 파일의 모든 위치를 나열하고 싶지 않다고 가정 해 봅시다. rsync를 동기화 할 파일을 "기억"하고 --delete의 영향을받는 파일 만 만드는 방법이 있습니까?
jkrzefski

죄송합니다, 귀하의 질문을 잘못 읽었습니다. 소스에 추가하고 싶지만 대상으로 업데이트하지 않았습니다. 나는 당신이 원하는 것을 할 수있는 방법이 있다고 생각하지만 조금만 숙고해야합니다. 편집 할 시간이 있으면 댓글을 달겠습니다.
Arronical

@jkrzefski 대상의 다른 스크립트에서 파일을 생성하고 소스에서 제외하려는 경우 해당 로그 파일의 대상을 다른 폴더로 변경하지 않는 이유는 무엇입니까? 아마도 동기화하지 않으면 덜 중요하기 때문일 수 있습니다.

6

당신이 언급 한 이후 : 나는 rsync로 제한되지 않습니다.

대상에 추가 파일을 추가 할 수 있도록 미러를 유지하는 스크립트

정확하게 설명하는 스크립트 아래.

스크립트는 상세 모드 (스크립트에서 설정) 로 실행할 수 있으며 , 백업 진행률 (미러링)을 출력합니다. 백업을 기록하는 데 사용할 수도 있습니다.

상세 옵션

여기에 이미지 설명을 입력하십시오


개념

1. 첫 번째 백업에서 스크립트는 다음과 같습니다.

  • 모든 파일과 디렉토리가 나열되는 파일을 대상 디렉토리에 작성합니다. .recentfiles
  • 대상 디렉토리에있는 모든 파일 및 디렉토리의 정확한 사본 (미러)을 작성합니다.

다음에 백업 등

  • 스크립트는 파일의 디렉토리 구조와 수정 날짜를 비교합니다. 소스의 새 파일과 디렉토리가 미러에 복사됩니다. 동시에 두 번째 (임시) 파일이 작성되어 소스 디렉토리에 현재 파일과 디렉토리가 나열됩니다. .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. 스크립트 헤드에서 verbose 옵션을 원하는 경우 변경하십시오.

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

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

속도

내 네트워크 드라이브 (NAS)에 약 40.000 개의 파일과 디렉토리가있는 10GB 디렉토리에서 스크립트를 테스트하여 rsync와 거의 같은 시간에 백업을 만들었습니다.

전체 디렉토리를 업데이트 하는 데는 40.000 파일에서 rsync보다 몇 초 밖에 걸리지 않았습니다. 스크립트는 내용을 마지막으로 백업 한 내용과 비교해야하기 때문에 당연한 일입니다.


안녕하세요 @ Aszune'sHeart는 스크립트 옵션을 추가했습니다. 모든 것이 분명하다면 언급하십시오.
Jacob Vlijm 2012 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.