rsyncが「ファイル名の変更」を正常に処理しないというのは本当ではありませんか?

rsyncが「ファイル名の変更」を正常に処理しないというのは本当ではありませんか?

バックアップツールを使用する場合duplicity、私は気づいた。ソースからファイルの名前を変更すると、データはネットワーク経由でターゲットに転送されます。、ちょっと残念です。内部duplicity使用のためにlibrsync見てみることにしましたrsync

これ建築wikiページ状態:

ハンドルの名前変更
移動または名前変更されたファイルは検出され、2回保存または転送されません。これは通常、ファイルまたはそのブロックのチェックサムを計算することを意味します。この機能が不足しているアプリケーションは、次の機能を組み合わせて補完することができます。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

進行状況のブロック固有の詳細を表示するには、2つの-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私の考えでは少し過剰だと思います)。

私の具体的な状況:私は名前を頻繁に変更せず、バックアップではなく同期リンク(1対1ではない)が欲しいです。そのためmv、rsyncを前後に実行するために、元々作成したスクリプトによってさらに実行されるコマンド(最後に新しいコマンドを追加)を作成するシェルコマンドファイルを作成することにしました。このスクリプトは多くのテストを受けていないため、リスクを取って実行する必要があり、改善のための提案を歓迎します。 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とマージする方法がわかりません。

関連情報