rsync가 "파일 이름 바꾸기"를 정상적으로 처리하지 않는다는 것이 사실이 아닙니까?

rsync가 "파일 이름 바꾸기"를 정상적으로 처리하지 않는다는 것이 사실이 아닙니까?

백업 도구를 사용하는 경우duplicity,나는 알아차렸다소스에서 파일 이름을 바꾸면 데이터가 네트워크를 통해 대상으로 다시 전송됩니다., 좀 아쉽네요. 내부 duplicity사용 으로 인해 librsync살펴보기로 결정했습니다 rsync.

이것건축 위키 페이지상태:

핸들 이름 바꾸기
이동되거나 이름이 변경된 파일은 감지되며 두 번 저장되거나 전송되지 않습니다. 이는 일반적으로 파일이나 해당 블록의 체크섬을 계산하는 것을 의미합니다. 이 기능이 부족한 애플리케이션은 다음과 같은 기능을 결합하여 보완할 수 있습니다.hsyncAUR , 동기 이름 바꾸기 전용입니다.

rsync: 핸들 이름 바꾸기: 아니요

이것이 정말로 의미하는 바는,사용 시 rsync10GB가 네트워크를 통해 대상으로 재전송되는 것을 방지할 수 있는 방법이 없습니다., 소스 머신의 이름을 다음으로 바꾸면 /test/10GBfile?/test/10GBfile_newname

의 오랜 인기를 감안할 때 rsync이를 처리할 더 좋은 방법이 있습니까?

답변1

rsync런타임 시를 제외하고는 상태를 유지하지 않기 때문에 이름 바꾸기를 추적하는 메커니즘이 없습니다 . 원본 머신에서 로 이름을 바꾸면 /test/10GBfile기본적으로 삭제된 항목과 생성된 항목만 표시됩니다./test/10GBfile_newnamersync10GBfile10GBfile_newname

매개변수 --fuzzy( )는 대상에서 잠재적인 데이터 소스를 -y식별하는 데 도움이 될 수 있으므로 파일 복사 대신 네트워크 복사를 방지할 수 있습니다. 그러나 (대부분) 파일 일치만 고려할 수 있습니다.10GBfile10GBfile_newname같은 디렉토리에따라서 귀하의 예는 일치하지만 이름 /test/10GBfile을 바꾸면 /test/otherdir/10GBfile_newname그렇지 않습니다.

또한 설명서( man rsync)에서는 를 사용하려는 경우 또는 사용하기 전에 잠재적인 일치 항목이 제거되지 않도록 사용해야 --delete한다고 제안합니다.--delay-updates--delete-after--fuzzy

# Prepare an uncompressible 100MB file
mkdir -p /tmp/test
dd bs=1M count=100 iflag=fullblock if=/dev/urandom >/tmp/test/file1

# Normal first-time copy
rsync -av --fuzzy --delete-after /tmp/test/ remote:/tmp/test

# Skip copy because unchanged
rsync -av --fuzzy --delete-after /tmp/test/ remote:/tmp/test

# Rename file (per your example)
mv /tmp/test/file1 /tmp/test/file2

# Fast copy because fuzzy match
rsync -av --fuzzy --delete-after /tmp/test/ remote:/tmp/test

진행 상황에 대한 블록별 세부 정보를 보려면 두 개의 -v플래그(예: )를 더 추가하세요 .rsync -avvv …

답변2

--fuzzy이미 답변을 받았지만 하드 링크와 관련된 또 다른 흥미로운 해킹이 있습니다.

첫 번째 전송 후

$ rsync -avHP --delete-after ~/family/Photos remotebox:backups

작업 디렉터리에 대한 하드 링크를 만듭니다.

$ cd ~/family
$ cp -rlp Photos Photos-work

그런 다음 사용할 수 있습니다

$ rsync -avHP --delete-after --no-inc-recursive ~/family/Photos ~/family/Photos-work remotebox:backups

새 구조를 리모컨으로 전송합니다.

그 이유와 작동 방식은 다음과 같습니다.

https://lincolnloop.com/blog/Detecting-file-moves-renames-rsync/

답변3

그 페이지에 옵션 패치를 --detect-renamed사용할 수 있다고 주장합니다 rsync 3.0.9. 여기에는 패치에 대한 링크가 있습니다.버그질라 토론. 내 것은 선택의 여지 rsync 3.1.3가 없었습니다 --detect-renamed. 언급된 논의는 현재 진행 중입니다:

2021-01-15 14:19:12 UTC 시간

이 기능 요청은 너무 오래되었으며 btrfs/zfs/etc가 rsync보다 더 최적화된 백업 솔루션이므로 관련성을 잃었습니다.

어떤 사람들은 "관련성 상실"에 동의하지 않으며 나는 동의하지 않는 사람들의 의견에 동의합니다.

저것레딧 페이지주장하다:

btrfs sync는 이 기능을 지원하지만 양쪽 끝에 btrfs가 필요합니다.

내가 생각하는 것에이라트라트말하는.

다음은 내 현재 솔루션입니다( git제 생각에는 약간 과잉이라고 생각합니다).

내 구체적인 상황: 나는 이름을 자주 바꾸지 않으며 백업이 아닌 동기화된 링크(일대일이 아닌)를 원합니다. 그래서 mvrsync를 앞뒤로 실행하기 위해 원래 작성한 스크립트에 의해 추가로 실행될 명령(마지막에 새 명령 추가)을 작성하는 쉘 명령 파일을 만들기로 결정했습니다 . 이 스크립트는 많은 테스트를 거치지 않았으므로 위험을 감수하고 실행해야 하며 개선을 위한 제안을 환영합니다. rsync --detect-renamed옵션이 곧 출시되기를 바랍니다 .

다음 전체 스크립트는 동기화 한쪽의 셸 파일 크기가 다른 쪽의 셸 파일보다 클 때 이를 별도로 처리하고 확실하지 않기 때문에 몇 가지 검사를 포함하기 때문에 꽤 깁니다(최근에 시작했기 때문에). 이 스크립트를 사용하여) comm프로그램 여부 올바르게 발견된 유일한 줄은 아마도 "정렬된"(맨 페이지별) 파일에 적용된다는 것입니다. 핵심은 다음과 같습니다.

# do renames / moves at both ends
cd $remote_path 
bash -c "$(comm --nocheck-order -3 -1 $f_RE $f_LO)"
cd $local_path 
bash -c "$(comm --nocheck-order -3 -2 $f_RE $f_LO)"

# merge files via temp file
(comm --nocheck-order -1 -2 $f_LO $f_RE) > $f_LO.3
(comm --nocheck-order -3 -1 $f_RE $f_LO) >> $f_LO.3
(comm --nocheck-order -3 -2 $f_RE $f_LO) >> $f_LO.3
cp $f_LO.3 $f_RE
mv $f_LO.3 --force $f_LO
rm $f_LO.1 $f_LO.2  

전체 쉘 기능:

#!/bin/bash
do_sync(){
    if [ -d $remote_path ]; then 
        
        # ===== workaround for renaming / moving (run manually made commands before rsync) ===== #
    
        # man comm: comm - compare two sorted files line by line
        complex_flag=0 # later set by script to 1 if changes identified from both sync directions
        to_rsync=1 # to run rsync by default
        f_RE=$remote_path/_rename_move.sh
        f_LO=$local_path/_rename_move.sh

        if [ -f $f_RE ]; then
             if [ -f $f_LO ]; then
                # if both exist, -gt greated than, stat --printf="%s" size in bytes
                if [ $(stat --printf="%s" $f_RE) -gt $(stat --printf="%s" $f_LO) ]; then
                    # small file (2nd) is fully contained in the beginning of larger file (maybe test binary mode more efficient)
                    # -1     suppress column 1 (lines unique to FILE1) : man comm
                    if [ -z "$(comm --nocheck-order -3 -1 $f_RE $f_LO)" ]; then
                        # run only additional commands 
                        cd $local_path 
                        bash -c "$(comm --nocheck-order -3 -2 $f_RE $f_LO)"
                        # overwrite small with larger one                     
                        cp $f_RE $f_LO
                    else complex_flag=1; fi
                # remote smaller than local
                elif [ $(stat --printf="%s" $f_RE) -lt $(stat --printf="%s" $f_LO) ]; then
                    # small file (1nd) is fully contained in the beginning of larger file (maybe test binary mode more efficient)
                    if [ -z "$(comm --nocheck-order -3 -2 $f_RE $f_LO)" ]; then
                        # run only additional commands
                        cd $remote_path
                        bash -c "$(comm --nocheck-order -3 -1 $f_RE $f_LO)"
                        # overwrite small with larger one                     
                        cp $f_LO $f_RE
                    else complex_flag=1; fi
                # same size but different contents
                elif [ ! $(sha256sum $f_RE | awk '{ print $1 }') = $(sha256sum $f_LO | awk '{ print $1 }') ]; then
                    complex_flag=1;
                fi
                # nothing to do if files are the same
             # if only remote exists                
             else
                cd $local_path && $f_RE
             fi

             # neither file was found to be part of another as a whole
             # expect changes (moves/renames) from both ends
             if [ $complex_flag -eq 1 ]; then

                # doing echo "$()" removes trailing empty lines compared to for some reason (TODO why?)

                # check that doing symmetrically with appending to local results in same number of lines in a file
                # and selecting matching in both and adding distinct from both too results in same number of lines in a file
                cp $f_RE $f_LO.1 && (comm --nocheck-order -3 -1 $f_RE $f_LO) >> $f_LO.1
                cp $f_LO $f_LO.2 && (comm --nocheck-order -3 -2 $f_RE $f_LO) >> $f_LO.2
                (comm --nocheck-order -1 -2 $f_LO $f_RE) > $f_LO.3
                (comm --nocheck-order -3 -1 $f_RE $f_LO) >> $f_LO.3
                (comm --nocheck-order -3 -2 $f_RE $f_LO) >> $f_LO.3
                counts_1="$(wc $f_LO.1 | awk '{ print $1,$2,$3 }')"
                counts_2="$(wc $f_LO.2 | awk '{ print $1,$2,$3 }')"
                counts_3="$(wc $f_LO.3 | awk '{ print $1,$2,$3 }')"
                # same counts, Ok
                if [ $counts_1 = $counts_2 ] && [ $counts_2 = $counts_3 ]; then
                    cd $remote_path 
                    bash -c "$(comm --nocheck-order -3 -1 $f_RE $f_LO)"
                    cd $local_path 
                    bash -c "$(comm --nocheck-order -3 -2 $f_RE $f_LO)"
                    cp $f_LO.3 $f_RE
                    mv $f_LO.3 --force $f_LO
                    rm $f_LO.1 $f_LO.2
                else
                    echo "========= manual intervention might be needed ==========="
                    echo "Results of analysis of $f_LO & $f_RE via [comm] app has not matched;"
                    echo "renaming/moving not performed;"
                    echo "rsync of $local_path & $remote_path not performed; see differences between files:"
                    echo "$f_LO.1, $f_LO.2, $f_LO.3"
                    echo "========================================================="
                    to_rsync=0
                fi
         fi   
        # if only local exists
        elif [ -f $f_LO ]; then
            cd $remote_path && $f_LO
        fi

        # ===== end of workaround ===== #

        if [ $to_rsync -eq 1 ];then
            rsync $options $local_path/ $remote_path
            rsync $options $remote_path/ $local_path
            rsync $options $local_path/ $remote_path
        fi

        # below is to move old versions away 
        find "$local_path" -path "$local_path/prevs" -prune -o -name '*.bak' -exec mv "{}" "$local_path/prevs" \;
        find "$remote_path" -path "$remote_path/prevs" -prune -o -name '*.bak' -exec mv "{}" "$remote_path/prevs" \;

# previous versions, prune works "more correct", forgot why
#        find $local_path -maxdepth 1 -name '*.bak' -exec mv "{}" $local_path/prevs \;
#        find $remote_path -maxdepth 1 -name '*.bak' -exec mv "{}" $remote_path/prevs \;
    else
        echo $remote_path is not available
    fi
}

# trailing / would prevent proper pruning in find commands
local_path=/home/$(id -un)/Documents
remote_path=/media/$(id -un)/Projects
do_sync

정답은https://serverfault.com/questions/489289/handling-renamed-files-or-directories-in-rsync내가 이해한 바로는 몇 가지 단점이 있습니다.

하드 링크 사용: 대부분의 시스템은 디렉토리에 대한 하드 링크를 지원하지 않으며 어느 쪽의 이름이 변경되었는지 확인하지 않습니다(백업은 가능하지만 동기화는 불가능함).

stat filename파일의 어느 쪽 이름이 바뀌었는지 확인하는 데 사용할 수 있지만 rsync와 병합하는 방법을 모르겠습니다.

관련 정보