Comparaison du contenu de deux répertoires

73

J'ai deux répertoires qui devraient contenir les mêmes fichiers et avoir la même structure de répertoires.

Je pense qu'il manque quelque chose dans l'un de ces répertoires.

À l'aide du shell bash, existe-t-il un moyen de comparer mes répertoires et de voir si l'un d'entre eux manque des fichiers présents dans l'autre?

    
posée AndreaNobili 16.02.2014 - 17:54
la source

9 réponses

49

Un bon moyen de faire cette comparaison consiste à utiliser find avec md5sum , puis un diff .

Exemple

Utilisez find pour répertorier tous les fichiers du répertoire, puis calculez le hachage md5 pour chaque fichier et transmettez-le trié par nom de fichier à un fichier:

find /dir1/ -type f -exec md5sum {} + | sort -k 2 > dir1.txt

Effectuez la même procédure dans un autre répertoire:

find /dir2/ -type f -exec md5sum {} + | sort -k 2 > dir2.txt

Comparez ensuite les deux fichiers de résultats avec diff :

diff -u dir1.txt dir2.txt

Ou en tant que commande unique utilisant la substitution de processus:

diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2) <(find /dir2/ -type f -exec md5sum {} + | sort -k 2)

Cette stratégie est très utile lorsque les deux répertoires à comparer ne se trouvent pas sur le même ordinateur et que vous devez vous assurer que les fichiers sont égaux dans les deux répertoires.

Un autre bon moyen de faire le travail consiste à utiliser la commande diff de Git (peut poser des problèmes lorsque les fichiers ont des autorisations différentes - > chaque fichier est alors répertorié dans la sortie):

git diff --no-index dir1/ dir2/
    
réponse donnée Adail Junior 09.01.2017 - 21:05
la source
63

Vous pouvez utiliser la commande diff exactement comme pour les fichiers:

diff <directory1> <directory2>

Si vous souhaitez également voir les sous-dossiers et les fichiers, vous pouvez utiliser l'option -r :

diff -r <directory1> <directory2>
    
réponse donnée Alex R. 16.02.2014 - 17:59
la source
16

Si vous n'utilisez pas bash, vous pouvez le faire en utilisant diff avec --brief et --recursive :

$ diff -rq dir1 dir2 
Only in dir2: file2
Only in dir1: file1

Le man diff inclut les deux options:

-q, --brief
report only when files differ

-r, --recursive
recursively compare any subdirectories found

    
réponse donnée Braiam 16.02.2014 - 22:19
la source
13

Voici une alternative, pour comparer uniquement les noms de fichiers, et non leur contenu:

diff <(cd folder1 && find . | sort) <(cd folder2 && find . | sort)

C’est un moyen simple de répertorier les fichiers manquants, mais bien sûr, il ne détectera pas les fichiers portant le même nom mais un contenu différent!

(J'utilise personnellement mon propre script diffdirs , mais cela fait partie d'une bibliothèque plus grande .)

    
réponse donnée joeytwiddle 16.02.2014 - 18:35
la source
3

Si vous voulez rendre chaque fichier extensible et pliable, vous pouvez diriger la sortie de diff -r dans Vim.

Donnons tout d'abord à Vim une règle de pliage:

mkdir -p ~/.vim/ftplugin
echo "set foldexpr=getline(v:lnum)=~'^diff.*'?'>1':1 foldmethod=expr fdc=2" >> ~/.vim/ftplugin/diff.vim

Maintenant, simplement:

diff -r dir1 dir2 | vim -

Vous pouvez appuyer sur zo et zc pour ouvrir et fermer des plis. Pour sortir de Vim, appuyez sur :q<Enter>

    
réponse donnée joeytwiddle 06.03.2016 - 05:25
la source
3

Inspiré par la réponse de Sergiy, j’ai écrit mon propre script Python pour comparer deux répertoires.

Contrairement à beaucoup d'autres solutions, il ne compare pas le contenu des fichiers. De plus, il n’entre pas dans les sous-répertoires qui manquent dans l’un des répertoires. La sortie est donc assez concise et le script fonctionne rapidement avec les grands répertoires.

#!/usr/bin/env python3

import os, sys

def compare_dirs(d1: "old directory name", d2: "new directory name"):
    def print_local(a, msg):
        print('DIR ' if a[2] else 'FILE', a[1], msg)
    # ensure validity
    for d in [d1,d2]:
        if not os.path.isdir(d):
            raise ValueError("not a directory: " + d)
    # get relative path
    l1 = [(x,os.path.join(d1,x)) for x in os.listdir(d1)]
    l2 = [(x,os.path.join(d2,x)) for x in os.listdir(d2)]
    # determine type: directory or file?
    l1 = sorted([(x,y,os.path.isdir(y)) for x,y in l1])
    l2 = sorted([(x,y,os.path.isdir(y)) for x,y in l2])
    i1 = i2 = 0
    common_dirs = []
    while i1<len(l1) and i2<len(l2):
        if l1[i1][0] == l2[i2][0]:      # same name
            if l1[i1][2] == l2[i2][2]:  # same type
                if l1[i1][2]:           # remember this folder for recursion
                    common_dirs.append((l1[i1][1], l2[i2][1]))
            else:
                print_local(l1[i1],'type changed')
            i1 += 1
            i2 += 1
        elif l1[i1][0]<l2[i2][0]:
            print_local(l1[i1],'removed')
            i1 += 1
        elif l1[i1][0]>l2[i2][0]:
            print_local(l2[i2],'added')
            i2 += 1
    while i1<len(l1):
        print_local(l1[i1],'removed')
        i1 += 1
    while i2<len(l2):
        print_local(l2[i2],'added')
        i2 += 1
    # compare subfolders recursively
    for sd1,sd2 in common_dirs:
        compare_dirs(sd1, sd2)

if __name__=="__main__":
    compare_dirs(sys.argv[1], sys.argv[2])

Si vous l'enregistrez dans un fichier nommé compare_dirs.py , vous pouvez l'exécuter avec Python3.x:

python3 compare_dirs.py dir1 dir2

Exemple de sortie:

[email protected]:~$ python3 compare_dirs.py old/ new/
DIR  old/out/flavor-domino removed
DIR  new/out/flavor-maxim2 added
DIR  old/target/vendor/flavor-domino removed
DIR  new/target/vendor/flavor-maxim2 added
FILE old/tmp/.kconfig-flavor_domino removed
FILE new/tmp/.kconfig-flavor_maxim2 added
DIR  new/tools/tools/LiveSuit_For_Linux64 added

P.S. Si vous devez comparer les tailles de fichier et les hachages de fichier pour les modifications éventuelles, j’ai publié un script mis à jour ici: link

    
réponse donnée Andriy Makukha 16.01.2018 - 11:01
la source
3

Tâche assez facile à réaliser en python:

python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' DIR1 DIR2

Remplacez les valeurs réelles par DIR1 et DIR2 .

Voici un exemple d'exécution:

$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Desktop
SAME
$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Pictures/
DIFF

Par souci de lisibilité, voici un script réel au lieu de one-liner:

#!/usr/bin/env python
import os, sys

d1 = os.listdir(sys.argv[1])
d2 = os.listdir(sys.argv[2])
d1.sort()
d2.sort()

if d1 == d2:
    print("SAME")
else:
    print("DIFF")
    
réponse donnée Sergiy Kolodyazhnyy 14.11.2016 - 07:12
la source
2

Peut-être qu'une option consiste à exécuter rsync deux fois

rsync -r -n -t -v --progress -c -s /dir1/ /dir2/

Avec la ligne précédente, vous obtiendrez des fichiers qui sont dans dir1 et qui sont différents (ou manquants) dans dir2. Aussi des dossiers avec une date différente.

rsync -r -n -t -v --progress -c -s /dir2/ /dir1/

Idem pour dir2

#from the rsync --help :
-r, --recursive             recurse into directories
-n, --dry-run               perform a trial run with no changes made
-t, --times                 preserve modification times
-v, --verbose               increase verbosity
    --progress              show progress during transfer
-c, --checksum              skip based on checksum, not mod-time & size
-s, --protect-args          no space-splitting; only wildcard special-chars

Vous pouvez supprimer l’option -n pour effectuer les modifications. Il s’agit de copier la liste des fichiers dans le deuxième dossier.

Dans ce cas, une bonne option est peut-être d’utiliser -u pour éviter d’écraser les fichiers les plus récents.

-u, --update                skip files that are newer on the receiver
    
réponse donnée Ferroao 17.12.2017 - 00:26
la source
0

Je vais ajouter à cette liste une alternative à NodeJs que j'ai écrite il y a quelque temps.

dir-comparer

npm install dir-compare -g
dircompare dir1 dir2
    
réponse donnée gliviu 20.02.2018 - 21:51
la source

Lire d'autres questions sur les étiquettes