rsync:フォルダーを同期しますが、ターゲットに余分なファイルを保持します


10

私は始めてrsync、ローカルシステム上の2つのフォルダーを同期させるためにそれを使用しようとしました。時間の経過とともにコンテンツが変化するソースフォルダー(一部のファイルが追加され、一部の変更があり、一部が削除される)と、ほぼソースのミラーにしたいターゲットフォルダーがあります。だから私が試したのは次のようにrsyncを使っていた:

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

これにより、ターゲットのコンテンツがソースのコンテンツとまったく同じに保たれます。ただし、いくつかのファイルをターゲットに追加してソースには追加できないようにしたいのですが、rsyncを実行するたびにそれらのファイルを削除したくありません。一方、同期され、その後ソースで削除されたファイルは、引き続き削除する必要があります。

除外したいすべてのファイルのコマンドを変更せずにこれを行う方法はありますか?

更新:私はrsyncに限定されていないことを言及する必要があります。別のプログラムがその仕事を成し遂げたとしても、それは問題ありません。私はrsyncを使用してこれを解決しようとしました。


こんにちは@AszunesHeart、好奇心旺盛ですが、答えをテストしましたか?
Jacob Vlijm 2017

--deleteオプションを削除してみましたか?これは、Robocopyの/ MIRオプションに似ています。
SDsolar 2017

回答:


9

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.txtcommon_name.jpgなど

これが私が望んでいたことをするかどうかはわかりません。また、ターゲットに追加されるすべてのファイルまたはフォルダーをリストすることは実際的ではありません。自動的にそれを行う方法が欲しいです。ターゲットに複数のログファイルを生成するさまざまなスクリプトがあり(これもターゲットにあります)、rsync_exclude-fileにそれらのファイルのすべての場所をリストしたくないとします。rsyncに同期されたファイルを「記憶」させ、それらに--deleteの影響のみを与える方法はありますか?
jkrzefski 2016

申し訳ありませんが、私はあなたの質問を読み間違えましたが、ソースに追加したかったのですが、ターゲットに更新されないようにしています。あなたがやりたいことをする方法はあると思いますが、少し考えなければなりません。編集する時間になったらコメントします。
アロニカル2016

@jkrzefskiターゲット内の別のスクリプトからファイルを作成していて、それらをソースから除外したい場合は、それらのログファイルの宛先を別のフォルダーに変更しないのはなぜですか。おそらく、それらを同期していない場合、それらはそれほど重要ではないためです。

6

あなたが言及したので:私はrsyncに限定されていません:

ミラーを維持するスクリプト。ターゲットにファイルを追加できます。

あなたが説明したとおりのことを行うスクリプトの下。

スクリプトは冗長モード(スクリプトで設定する)で実行でき、バックアップ(ミラーリング)の進行状況を出力します。これはバックアップのログにも使用できると言う必要はありません。

冗長オプション

ここに画像の説明を入力してください


コンセプト

1.最初のバックアップで、スクリプトは:

  • すべてのファイルとディレクトリがリストされているファイルを(ターゲットディレクトリに)作成します。 .recentfiles
  • ターゲットディレクトリ内のすべてのファイルとディレクトリの正確なコピー(ミラー)を作成します

2.次回以降のバックアップ

  • スクリプトは、ファイルのディレクトリ構造と変更日を比較します。ソース内の新しいファイルとディレクトリがミラーにコピーされます。同時に、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個のファイルとディレクトリがある10 GBのディレクトリでスクリプトをテストしました。rsyncとほぼ同じ時間でバックアップが作成されました。

スクリプトが最後に作成されたバックアップと内容を比較する必要があるため、ディレクトリ全体の更新はrsyncよりも数秒だけ長く、40.000ファイルで完了しました。


こんにちは@ Aszune'sHeartがスクリプトオプションを追加しました。すべてが明確な場合は言及してください。
Jacob Vlijm 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.