ディレクトリを比較しますが、ファイルの内容は比較しません


21

diff -rを使用するとこのタスクを実行できますが、diffはファイルのコンテンツをチェックするため、非常に時間がかかります。

2つのファイルのサイズ、最終変更などが同じであると判断できるものが必要です。ただし、ファイルを少しずつチェックすることはありません(たとえば、ビデオには時間がかかります)

他の方法はありますか?

回答:


20

デフォルトでは、rsyncはファイルのメタデータのみを比較します。

rsync -n -a -i --delete source/ target/

説明:

  • -n 実際にコピーまたは削除しない<-これは重要!! 1
  • -a タイムスタンプや属性など、ファイルのすべてのメタデータを比較します
  • -i ファイルごとに1行の情報を印刷します
  • --delete ソースにないファイルも報告する

注:ディレクトリ名にスラッシュを追加することが重要です。これはrsyncのことです。

同じファイルの行を表示したい場合は、-i2回提供してください

rsync -n -a -ii --delete source/ target/

出力例:

*deleting   removedfile   (file in target but not in source)
.d..t...... ./            (directory with different timestamp)
>f.st...... modifiedfile  (file with different size and timestamp)
>f+++++++++ newfile       (file in source but not in target)
.f          samefile      (file that has same metadata. only with -ii)

rsyncはメタデータのみを比較することに注意してください。つまり、ファイルの内容は変更されたがメタデータが同じままである場合、rsyncはそのファイルが同じであると報告します。これはありそうもないシナリオです。そのため、メタデータが同じであるときにデータが同じであると信頼するか、ファイルデータをビットごとに比較する必要があります。

ボーナス:進捗情報については、こちらを参照してください:rsyncの終了までの時間または作業の見積もり?


1
スラッシュsource/とはtarget/、両方のも非常に重要です!(これらを使用しない場合、ソースおよびターゲットのディレクトリ名と子ファイル名を比較するため、すべてのファイル名が異なります。)
peschü

先にあなたのコメントを読んでいたら、これはとても重要です!ソースのスラッシュのみを省略し、ターゲットのファイルがとして表示されない*deletingのに、ソースにあるファイルのみが表示されるのはなぜかと思っていました。スラッシュは誤って忘れやすいため、もっともらしいが間違った出力になります。
user643011

3

使用-q--briefと)オプションをdiff -rdiff -qr)。infoGNU のページからdiff

1.6異なるファイルの要約

ファイルが異なるかどうかだけを知りたい場合で、その違いを気にしない場合は、サマリー出力形式を使用できます。この形式では、ファイル間の違いを表示する代わりに、diff' simply reports whether files differ. The-brief '( `-q')オプションがこの出力形式を選択します。

この形式は、2つのディレクトリの内容を比較するときに特に役立ちます。また、「diff」は違いがあることがわかるとすぐにファイルの分析を停止できるため、通常の行ごとの比較よりもはるかに高速です。

これは、行ごとに比較するのではなく、ファイル全体を比較するため、プロセッサ(探しているもの)が大幅に高速化されます。


1
-qの問題は、通常と比較し、違いが見つかると停止することです(通常モードの場合は比較を続けます)。
eez0

2

ファイル名、mtimes、およびファイルサイズがすべて同じであることを確認する簡単なpythonスクリプトを次に示します。

import os
import sys

def getStats(path):
    for pathname, dirnames, filenames in os.walk(path):
        for filename in ( os.path.join(pathname, x) for x in filenames ):
            stat = os.stat(filename)
            yield filename[len(path):], stat.st_mtime, stat.st_size

sys.exit(tuple(getStats(sys.argv[1])) != tuple(getStats(sys.argv[2])))

1

2つのファイルシステムブランチのファイルが異なるかどうか(ファイルの内部を調べることなく)だけを知る必要がある場合は、次のようにすることができます。

find /opt/branch1 -type f | sort | xargs -i md5sum {} >/tmp/branch1;
find /opt/branch2 -type f | sort | xargs -i md5sum {} >/tmp/branch2;
diff /tmp/branch1 /tmp/branch2;

HTH


0

クリスダウンのスクリプトに基づいて、このスクリプトはもう少し「視覚的」です。2つの引数folder1folder2で呼び出して、最初のフォルダーを検索し、各ファイルについて2番目のフォルダー内の対応するファイルを検索します。見つかった場合、相対パスは緑色で印刷され、変更された時間またはサイズが異なる場合は黄色で印刷され、見つからなかった場合は赤色で印刷されます。

#!/usr/bin/env python

import os
import sys
from termcolor import colored

def compare_filestats(file1,file2):
    """
    Compares modified time and size between two files.
    Return:
        -1 if file1 or file2 does not exist
         0 if they exist and compare equal
         1 if they have different modified time, but same size
         2 if they have different size, but same modified time
         3 if they have different size, and different modified time
    """

    if not os.path.exists(file1) or not os.path.exists(file2):
        return -1

    stat1 = os.stat(file1)
    stat2 = os.stat(file2)

    return (stat1.st_mtime != stat2.st_mtime) \
        + 2*(stat1.st_size != stat2.st_size)

def compare_folders(folder1,folder2):
    """
    folder1: serves as reference and will be walked through
    folder2: serves as target and will be querried for each file in folder1

    Prints colored status for each file in folder1:
        missing: file was not found in folder2 
        mtime  : modified time is different
        size   : filesize is different
        ok     : found with same filestats
    """
    for dirpath, dirnames, filenames in os.walk(folder1):
        for file1 in ( os.path.join(dirpath, x) for x in filenames ):
            relpath = file1[len(folder1):]
            file2 = os.path.join( folder2, relpath )
            comp = compare_filestats(file1,file2)

            if comp < 0:
                status = colored('[missing]','red')
            elif comp == 1:
                status = colored('[mtime  ]','yellow')
            elif comp >= 2:
                status = colored('[size   ]','yellow')
            else:
                status = colored('[ok     ]','green')

            print status, relpath

if __name__ == '__main__':
    compare_folders(sys.argv[1],sys.argv[2])

これは、2つのフォルダーが同じかどうかを判断するに十分ではないことに注意してください。実際には、フォルダーが同じであるかどうかだけを知りたい場合は、 Chrisのスクリプトの方が優れています。フォルダーごとに何が欠けているか、または何が異なるかを知りたい場合は、私のスクリプトが教えてくれます。

注:termcolorをインストールする必要がありますpip install termcolor


0

構造とファイルに関する基本情報のみを比較したい場合は、次のようなものを試すことができます。

diff <(cd $DIR1 && ls -laR) <(cd $DIR2 && ls -laR)

私はそれをテストしなかったので、編集は大歓迎です:)


2
ディレクトリ名自体も結果に含まれるため、これは機能しません。
クリスダウン

ディレクトリ名を持つ最初の列を除外するとどうなりますか?like <(ls -laR | awk '{$ 1 = ""; print}')
Volodymyr

すべての行がディレクトリ名ではないため、適切に機能しません。
クリスダウン

それぞれ<()が独自の環境を持っているという事実を活用してください。編集済み。
CVn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.