Porównaj katalogi, ale nie zawartość plików

21

Z diff -r mogę wykonać to zadanie, jednak trwa to tak długo, ponieważ diff sprawdza zawartość pliku.

Chcę czegoś, co określi, że dwa pliki są takie same pod względem wielkości, ostatniej modyfikacji itp. Ale nie sprawdzam pliku po kawałku (na przykład wideo trwa tak długo)

Czy jest jakiś inny sposób?

eez0
źródło

Odpowiedzi:

20

rsync domyślnie porównuje tylko metadane plików.

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

wyjaśnienie:

  • -n nie kopiuj ani nie usuwaj <- JEST WAŻNE !! 1
  • -a porównaj wszystkie metadane pliku, takie jak znacznik czasu i atrybuty
  • -i wydrukuj jeden wiersz informacji na plik
  • --delete zgłaszaj także pliki, które nie są źródłowe

Uwaga: ważne jest, aby dodać nazwy katalogów ukośnikiem. to jest rsync.

jeśli chcesz również zobaczyć linie drukowane dla plików, które są identyczne, podaj -idwa razy

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

przykładowe dane wyjściowe:

*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)

pamiętaj, że rsync porównuje tylko metadane. oznacza to, że jeśli zawartość pliku ulegnie zmianie, ale metadane pozostaną takie same, to rsync zgłosi, że plik jest taki sam. jest to mało prawdopodobny scenariusz. więc albo ufaj, że gdy metadane są takie same, to dane są takie same, albo musisz porównywać dane pliku krok po kroku.

bonus: aby uzyskać informacje o postępie, zobacz tutaj: Oszacować czas lub pracę do ukończenia dla rsync?

lesmana
źródło
1
Cięcia source/i target/są również bardzo ważne! (Bez nich
porównasz
Chciałbym przeczytać Twój komentarz wcześniej, to takie ważne! Pominąłem ukośnik tylko w źródle, a potem zastanawiałem się, dlaczego pliki w celu nie pojawiły się jako *deleting, ale pojawiły się tylko pliki w źródle. Cięcia można łatwo przypadkowo zapomnieć, a następnie uzyskać wiarygodny, ale zły wynik.
user643011
3

Użyj opcji -q( --brief) z diff -r( diff -qr). Ze infostrony GNU diff:

1.6 Podsumowanie, które pliki się różnią

Jeśli chcesz tylko dowiedzieć się, czy pliki są różne i nie obchodzi Cię, jakie są różnice, możesz użyć podsumowującego formatu wyjściowego. W tym formacie zamiast pokazywać różnice między plikami, diff' simply reports whether files differ. Theopcja --brief '(`-q') wybiera ten format wyjściowy.

Ten format jest szczególnie przydatny podczas porównywania zawartości dwóch katalogów. Jest to również znacznie szybsze niż wykonywanie normalnych porównań linia po linii, ponieważ `diff 'może przestać analizować pliki, gdy tylko dowie się, że są jakieś różnice.

Nie będzie to porównywać linia po linii, ale raczej plik jako całość, co znacznie przyspieszy procesor (czego „szukasz”).

laebshade
źródło
1
Problem z - q polega na tym, że porównuje normalne, a gdy znajdzie różnicę, zatrzymuje się (gdyby był to tryb normalny, to ciągle się porównuje), więc jeśli ogromne pliki są takie same, to będzie trwać bardzo długo.
eez0
2

Oto szybki skrypt Pythona, który sprawdzi, czy nazwy plików, mtimes i rozmiary plików są takie same:

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])))
Chris Down
źródło
1

Jeśli potrzebujesz tylko wiedzieć, czy pliki z dwóch gałęzi systemu plików są różne (bez przeglądania plików wewnątrz), możesz zrobić coś takiego:

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

Chaky
źródło
0

Oparty na skrypcie Chrisa Downa, ten skrypt jest trochę bardziej „wizualny”. Nazywając ją z dwoma argumentami folder1i folder2to idzie pierwszy folder i dla każdego pliku wyszukuje odpowiedni plik w drugim folderze. Jeśli zostanie znaleziona, ścieżka względna zostanie wydrukowana na zielono, jeśli mają inny zmodyfikowany czas lub rozmiar, zostanie wydrukowana na żółto, a jeśli nie zostanie znaleziona, zostanie wydrukowana na czerwono.

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

Pamiętaj, że nie jest to wystarczające, aby zdecydować, czy dwa foldery są takie same, musisz to zrobić w obie strony, aby się upewnić. W praktyce, jeśli chcesz tylko wiedzieć, czy foldery są takie same , skrypt Chrisa jest lepszy. Jeśli chcesz wiedzieć, co brakuje lub różni się z jednego folderu do drugiego , mój skrypt Ci to powie.

UWAGA: trzeba będzie zainstalowany termcolor, pip install termcolor.

Sheljohn
źródło
0

Jeśli chcesz porównać tylko strukturę i podstawowe informacje o plikach, możesz spróbować czegoś takiego:

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

Nie testowałem tego, więc wszelkie zmiany są mile widziane :)

Włodzimierz
źródło
2
To nie zadziała, ponieważ same nazwy katalogów również będą w wynikach.
Chris Down
co jeśli wykluczymy pierwszą kolumnę z nazwami katalogów? jak <(ls -laR | awk '{$ 1 = ""; print}')
Volodymyr
Nie wszystkie wiersze są nazwami katalogów, więc to nie będzie działać poprawnie.
Chris Down
Skorzystaj z faktu, że każdy <()ma swoje własne środowisko. Edytowane.
CVn