Сравнить каталоги, но не содержимое файлов

21

С помощью diff -r я могу выполнить эту задачу, однако это занимает много времени, поскольку diff проверяет содержимое файла.

Я хочу что-то, что определяет, что два файла одинаковы в отношении их размера, последнего изменения и т. Д. Но нет проверки по крупицам файла (например, видео занимает слишком много времени)

Есть ли другой способ?

eez0
источник

Ответы:

20

По умолчанию rsync сравнивает только метаданные файла.

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

объяснение:

  • -n на самом деле не копировать и не удалять <- ЭТО ВАЖНО !! 1
  • -a сравнить все метаданные файла, такие как отметка времени и атрибуты
  • -i печатать одну строку информации на файл
  • --delete также файлы отчетов, которых нет в источнике

примечание: важно добавлять имена каталогов через косую черту. это rsync вещь.

если вы также хотите увидеть строки, напечатанные для идентичных файлов, укажите -iдважды

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?

lesmana
источник
1
Косые черты, source/а target/также оба очень важны! (Без них вы будете сравнивать имена исходных и целевых каталогов с именами дочерних файлов, поэтому все имена файлов будут отличаться.)
peschü
Жаль, что я не прочитал ваш комментарий ранее, это так важно! Я опустил косую черту только в исходном коде, а затем мне стало интересно, почему файлы в target не отображаются так же *deleting, как файлы, находящиеся только в исходном коде. Косые черты легко забыть случайно, и тогда вы получите правдоподобный, но неправильный вывод.
user643011
3

Используйте -q( --briefопция) с diff -r( diff -qr). Со infoстраницы для GNU diff:

1.6 Подводя итог, какие файлы отличаются

Если вы хотите узнать, отличаются ли файлы, и вам все равно, в чем заключаются различия, вы можете использовать формат итогового вывода. В этом формате вместо отображения различий между файлами diff' simply reports whether files differ. Theопция --brief '(`-q') выбирает этот формат вывода.

Этот формат особенно полезен при сравнении содержимого двух каталогов. Это также намного быстрее, чем обычное построчное сравнение, потому что diff может прекратить анализ файлов, как только узнает, что есть какие-то различия.

Это будет сравнивать не построчно, а файл в целом, что значительно ускоряет процессор (что вы ищете).

laebshade
источник
1
Проблема - q заключается в том, что он сравнивает обычные значения, и когда находит разницу, останавливается (если в обычном режиме он продолжает сравнивать), поэтому, если огромные файлы одинаковы, он будет работать долго.
eez0
2

Вот быстрый скрипт на python, который проверит, что имена файлов, mtimes и размеры файлов одинаковы:

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

Если вам нужно только узнать, отличаются ли файлы из двух ветвей файловой системы (не заглядывая внутрь файлов), вы можете сделать что-то вроде этого:

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;

НТН

Chaky
источник
0

Основанный на сценарии Криса Дауна, этот сценарий немного более «визуален». Назвав его с двумя аргументами folder1и folder2, он проходит первую папку и для каждого файла ищет соответствующий файл во второй папке. Если он найден, относительный путь печатается зеленым цветом, если они имеют различное измененное время или размер, он печатается желтым цветом, а если он не найден, то печатается красным.

#!/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])

Обратите внимание , что это не достаточно , чтобы решить , следует ли две папки такие же, вам нужно будет запустить его в обоих направлениях , чтобы убедиться. На практике, если вы просто хотите узнать , одинаковы ли папки , тогда сценарий Криса лучше. Если вы хотите узнать, что отсутствует или отличается от одной папки к другой , то мой скрипт скажет вам.

ПРИМЕЧАНИЕ: вам понадобится установить termcolor pip install termcolor.

Sheljohn
источник
0

Если вы хотите сравнить только структуру и некоторую базовую информацию о файлах, вы можете попробовать что-то вроде этого:

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

Я не проверял это, поэтому любые изменения приветствуются :)

Владимир
источник
2
Это не будет работать, так как сами имена каталогов также будут в результатах.
Крис Даун
Что если мы исключим первый столбец с именами каталогов? like <(ls -laR | awk '{$ 1 = ""; print}')
Владимир
Не все строки являются именами каталогов, поэтому они не будут работать должным образом.
Крис Даун
Воспользуйтесь тем, что у каждого <()своя среда. Ред.
CVN