Порівняйте каталоги, але не вміст файлів


21

За допомогою diff -r я можу виконати це завдання, однак це займає так багато часу, оскільки diff перевіряє вміст файлу.

Я хочу щось, що визначає, що два файли однакові за своїм розміром, останній модифікований і т. Д. Але не перевіряйте побітно файл (наприклад, відео займає так довго)

Чи є інший спосіб?

Відповіді:


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?


1
Слеші в source/і target/також дуже важливі! (Без них ви будете порівнювати імена джерел і цільових каталогів разом з іменами дочірніх файлів, тому всі назви файлів будуть відрізнятися.)
peschü

Я хотів би, щоб я прочитав ваш коментар раніше, це так важливо! Я пропустив косу рису тільки в джерелі, і тоді мені було цікаво, чому файли в цілі не відображаються як *deleting, але файли, які є в джерелі, лише з'являються. Штрихи легко випадково забути, і тоді ви отримаєте правдоподібний, але неправильний вихід.
user643011

3

Використовуйте -q( --briefопція) з diff -r( diff -qr). На infoсторінці для GNU diff:

1.6 Підведення підсумків, які файли відрізняються

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

Цей формат особливо корисний при порівнянні вмісту двох каталогів. Це також набагато швидше, ніж звичайне порівняння рядків за рядком, тому що "diff" може перестати аналізувати файли, як тільки дізнається, що є якісь відмінності.

Це не буде порівнювати по черзі, а файл у цілому, що значно прискорює процесор (що ви шукаєте).


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;

HTH


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.


0

Якщо ви хочете порівняти лише структуру та основну інформацію про файли, ви можете спробувати щось подібне:

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

Я не перевіряв цього, тому будь-які зміни можна вітати :)


2
Це не буде працювати, оскільки самі імена каталогів також будуть в результатах.
Кріс Даун

що робити, якщо ми будемо виключати перший стовпець з іменами каталогу? like <(ls -laR | awk '{$ 1 = ""; print}')
Володимир

Не всі рядки є іменами каталогів, тому вони не працюватимуть належним чином.
Кріс Даун

Скористайтеся тим, що у кожного <()є своє оточення. Відредаговано.
CVn
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.