Comparer les répertoires mais pas le contenu des fichiers

21

Avec diff -r, je peux faire cette tâche, mais cela prend si longtemps car diff vérifie le contenu du fichier.

Je veux quelque chose qui détermine que deux fichiers sont identiques en ce qui concerne leur taille, leur dernière modification, etc.

Est-ce qu'il y a un autre moyen?

eez0
la source

Réponses:

20

rsync, par défaut, compare uniquement les métadonnées de fichier.

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

explication:

  • -n ne copiez ni ne supprimez pas <- C'EST IMPORTANT !! 1
  • -a comparer toutes les métadonnées du fichier comme l'horodatage et les attributs
  • -i imprimer une ligne d'informations par fichier
  • --delete signaler également les fichiers qui ne sont pas dans la source

remarque: il est important d'ajouter les noms de répertoire avec une barre oblique. c'est une chose rsync.

si vous souhaitez également voir les lignes imprimées pour les fichiers identiques, fournissez -ideux fois

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

exemple de sortie:

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

rappelez-vous que rsync compare uniquement les métadonnées. cela signifie que si le contenu du fichier a changé mais que les métadonnées sont restées les mêmes, rsync signalera que le fichier est le même. c'est un scénario peu probable. alors soit confiance que lorsque les métadonnées sont identiques, les données sont identiques, soit vous devez comparer les données de fichier bit par bit.

bonus: pour des informations sur les progrès voir ici: Estimer le temps ou le travail restant pour terminer rsync?

lesmana
la source
1
Les barres obliques source/et target/sont aussi à la fois très important! (Sans eux, vous comparerez les noms des répertoires source et cible avec les noms des fichiers enfants, de sorte que tous les noms de fichiers différeront.)
peschü
J'aimerais avoir lu votre commentaire plus tôt, c'est tellement important! J'ai omis la barre oblique dans la source uniquement, puis je me demandais pourquoi les fichiers dans la cible ne s'affichaient pas comme *deleting, mais les fichiers, qui ne sont dans la source, ne s'affichaient pas. Les barres obliques sont faciles à oublier accidentellement et vous obtenez alors une sortie plausible mais erronée.
user643011
3

Utilisez la -q( --briefoption) avec diff -r( diff -qr). De la infopage pour GNU diff:

1.6 Résumer quels fichiers diffèrent

Lorsque vous souhaitez uniquement savoir si les fichiers sont différents et que vous ne vous souciez pas des différences, vous pouvez utiliser le format de sortie récapitulatif. Dans ce format, au lieu d'afficher les différences entre les fichiers, l' diff' simply reports whether files differ. Theoption --brief '(`-q') sélectionne ce format de sortie.

Ce format est particulièrement utile pour comparer le contenu de deux répertoires. C'est aussi beaucoup plus rapide que de faire des comparaisons normales ligne par ligne, car `diff 'peut arrêter l'analyse des fichiers dès qu'il sait qu'il y a des différences.

Cela ne comparera pas ligne par ligne, mais plutôt le fichier dans son ensemble, ce qui accélère considérablement le processeur (ce que vous recherchez).

abat-jour
la source
1
Le problème de -q est qu'il compare normalement et quand trouve une différence qui s'arrête (si c'était le mode normal, il continue de comparer), donc si les fichiers énormes sont les mêmes, cela durera beaucoup.
eez0
2

Voici un script python rapide qui vérifiera que les noms de fichiers, mtimes et tailles de fichiers sont tous les mêmes:

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
la source
1

Si vous avez seulement besoin de savoir si les fichiers de deux branches du système de fichiers sont différents (sans regarder à l'intérieur des fichiers), vous pouvez faire quelque chose comme ceci:

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
la source
0

Basé sur le script de Chris Down, ce script est un peu plus "visuel". L'appelant avec deux arguments folder1et folder2, il parcourt le premier dossier et pour chaque fichier recherche un fichier correspondant dans le deuxième dossier. S'il est trouvé, le chemin relatif est imprimé en vert, s'il a une heure ou une taille modifiée différente, il est imprimé en jaune et s'il n'est pas trouvé, il est imprimé en rouge.

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

Notez que cela ne suffit pas pour décider si les deux dossiers sont identiques, vous devrez l'exécuter dans les deux sens pour vous en assurer. En pratique, si vous voulez simplement savoir si les dossiers sont les mêmes , alors le script de Chris est meilleur. Si vous voulez savoir ce qui manque ou est différent d'un dossier à l'autre , mon script vous le dira.

REMARQUE: vous aurez besoin termcolor installé, pip install termcolor.

Sheljohn
la source
0

Si vous souhaitez comparer uniquement une structure et quelques informations de base sur les fichiers, vous pouvez essayer quelque chose comme ceci:

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

Je ne l'ai pas testé, donc toutes les modifications sont les bienvenues :)

Volodymyr
la source
2
Cela ne fonctionnera pas car les noms de répertoires eux-mêmes figureront également dans les résultats.
Chris Down
que se passe-t-il si nous excluons la première colonne avec les noms de répertoire? comme <(ls -laR | awk '{$ 1 = ""; print}')
Volodymyr
Toutes les lignes ne sont pas des noms de répertoire, donc cela ne fonctionnera pas correctement.
Chris Down
Profitez du fait que chacun <()a son propre environnement. Édité.
un CVn