
rsync
ソース リポジトリ (バージョン管理されている) のコンテンツを共有 NFS マウントに同期するプロセスがあります。
シナリオは (ひどいことですが)、他のコンテンツが別のソースから宛先フォルダーに同期されているため、宛先フォルダーにソース フォルダーよりも多くのコンテンツが含まれるというものです。たとえば、フォルダー構造は次のようになります。
ソース
a/a1.txt
a/a2.txt
b/b1.txt
行き先
a/a1.txt
a/a2.txt
a/a3.txt
b/b1.txt
c/c1.txt
(この例では、a/a3.txt
他c/c1.txt
の場所から宛先に同期されます。実際には、これには複数の他のソースが関係し、これらのコンテンツ/プロセスは影響を受けません。)
ここで、ソース フォルダーがa/a2.txt
ファイルを削除するとします。既存の設定を使用すると、このファイルは宛先で削除されませんが、を使用すると--delete
他のファイルが削除されるため、これを行わないようにする必要があります。
この rsync でどのよう--delete
に使用すれば要件を満たすことができますか? ソース ディレクトリはバージョン管理されているため、このディレクトリの前後を取得するのは簡単です。そのため、元のソース ディレクトリを参照として使用して差分バックアップを計算できますが、これが最善の方法でしょうか?
答え1
このように使用することはできませんrsync --delete
。これはステートレスであり、実行間でどのファイルが削除されたかの記録を保持しません。フラグは、ソースに存在しない宛先のすべてのファイルを削除するように--delete
指示するだけです。rsync
この制約付き削除を実装するには、独自の状態を維持する必要があると思います。 も も、これを実行することはできませrsync
ん。unison
以下は完全にエラーのない解決策ではなく、出発点です。(ただし、改行が埋め込まれているファイルなど、奇妙な名前のファイルも処理します。)
2 つのディレクトリsrc
とがあるとしますdst
。(この例では、dst
がローカルかリモートかは関係ありません。)
# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z > .state.src
バックアップを実行するたびに、次のコードを実行します。
# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/
# Determine the set of files to delete in "dst/"
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z | tee .state.src.new |
LC_ALL=C comm -z - -13 .state.src |
ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'
# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src
お使いのバージョンcomm
(私のものもそうです) が GNU coreutils 8.25 より古く、フラグがない場合は-z
、次の代替回避策を使用できます。
# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort > .state.src
バックアップを実行するたびに、次のコードを実行します。
# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/
# Determine the set of files to delete in "dst/"
( cd src && find . -type f -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort | tee .state.src.new |
LC_ALL=C comm -13 - .state.src |
tr '\0\n' '\n\0' |
ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'
# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src