Trouver les fichiers existant dans un répertoire mais pas dans l'autre [fermé]


295

J'essaie de trouver les fichiers existants dans un répertoire mais pas dans l'autre, j'ai essayé d'utiliser cette commande:

diff -q dir1 dir2

Le problème avec la commande ci-dessus qui trouve les fichiers dans dir1mais pas dans dir2ainsi que les fichiers dans dir2mais pas dans dir1,

J'essaie de trouver les fichiers dir1mais pas dir2seulement.

Voici un petit échantillon de ce à quoi mes données ressemblent

dir1    dir2    dir3
1.txt   1.txt   1.txt
2.txt   3.txt   3.txt
5.txt   4.txt   5.txt
6.txt   7.txt   8.txt

Une autre question me vient à l'esprit: comment puis-je trouver les fichiers dans dir1mais pas dans dir2ou dir3dans une seule commande?

Réponses:


390
diff -r dir1 dir2 | grep dir1 | awk '{print $4}' > difference1.txt

Explication:

  • diff -r dir1 dir2 montre quels fichiers sont uniquement dans dir1 et ceux uniquement dans dir2 et aussi les changements des fichiers présents dans les deux répertoires le cas échéant.

  • diff -r dir1 dir2 | grep dir1 montre quels fichiers sont uniquement en dir1

  • awk pour imprimer uniquement le nom de fichier.


5
Je voudrais greppour ^dir1sûr que je ne reçois pas d' dir1apparition plus tard dans le chemin.
Alfe

@Alfe Il peut être amélioré. J'utilise $4comme exemple. En fait, sur mon Ubuntu actuel, les diffréponses en italien. $4est correct pour les réponses en italien et en anglais, mais je ne suis pas sûr pour toutes les autres langues ...
asclepix

139

Cela devrait faire le travail:

diff -rq dir1 dir2

Options expliquées (via la page de manuel diff (1) ):

  • -r - Comparez récursivement tous les sous-répertoires trouvés.
  • -q - Afficher uniquement si les fichiers diffèrent.

8
Agréable! Mais je pense que cela devrait être étendu comme ça:diff -rq dir1 dir2 | grep 'Only in dir1/'
sobi3ch

2
Il s'agit d'une comparaison par contenu, mais cela peut prendre beaucoup de temps sur des disques lents.
Smeterlink

5
Juste une note sur l' -qoption: les pages de manuel ne disent que "Afficher uniquement si les fichiers diffèrent", pas comment il vérifie s'ils sont différents. J'ai parcouru le code source et découvert qu'il vérifie uniquement la taille des fichiers pour déterminer les différences, pas le contenu réel.
ryancdotnet

Concernant l' -qoption je ne peux pas reproduire qu'elle ne vérifie que la taille du fichier. Utilisation de GNU Diffutils 3.7 en comparant deux fichiers avec la même taille de fichier mais un contenu différent avec des diff -q file1 file2sorties Files file1 and file2 differ.
Stefan Schmidt

50
comm -23 <(ls dir1 |sort) <(ls dir2|sort)

Cette commande vous donnera des fichiers qui sont en dir1 et non en dir2.

À propos de <( )signe, vous pouvez le rechercher sur Google en tant que «substitution de processus».


ce serait bien de travailler aussi avec des sous-répertoires, je pense que cela (ls -R dir1|sort)pourrait faire l'affaire
ulkas

1
Cela fonctionnerait sur le mode de récupération OS X.
Anthony Vanover

@ulkas, la sortie peut être incorrecte si vous utilisez (ls -R dir|sort).
Andriy Makukha

3
vimdiff offre une comparaison visuelle beaucoup plus agréable avec la mise en évidence des couleurs:vimdiff <(ls dir1 |sort) <(ls dir2|sort)
Logan Reed

32

Une bonne façon de faire cette comparaison consiste à utiliser findavec md5sum, puis undiff .

Exemple:

Utilisez findpour répertorier tous les fichiers du répertoire, puis calculez le hachage md5 pour chaque fichier et dirigez-le vers un fichier:

find /dir1/ -type f -exec md5sum {} \; > dir1.txt

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

find /dir2/ -type f -exec md5sum {} \; > dir2.txt

Ensuite, comparez le résultat deux fichiers avec "diff":

diff dir1.txt dir2.txt

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

Une autre bonne façon de faire le travail est d'utiliser git

git diff --no-index dir1/ dir2/

Meilleures salutations!


1
Je ne suis pas allé git pourrait faire un diff sur des répertoires arbitraires qui ne sont pas dans un dépôt git ... génial !!! Cette réponse vient de résoudre un gros problème pour moi, merci
ViktorNova

17

Meld ( http://meldmerge.org/ ) fait un excellent travail pour comparer les répertoires et les fichiers qu'il contient.

Fusionner des répertoires


Sauf que meld fait un travail moche en ce qui concerne les fins de ligne ...
0xC0000022L

1
Jamais eu de problème avec les fins de ligne. Pouvez-vous détailler?
Catalin Hritcu

Oui, il n'a pas indiqué les fins de ligne. Cela a conduit (à plusieurs reprises) les développeurs à utiliser cet outil pour valider des modifications qui «corrigeaient» les fins de ligne en transformant un CRLF en CRLFLF, par exemple.
0xC0000022L

3
Il insiste également sur la lecture du contenu des fichiers, et est donc presque inutile avec les répertoires >> 1 Go.
Tomislav Nakic-Alfirevic

13

Le plugin DirDiff de vim est un autre outil très utile pour comparer les répertoires.

vim -c "DirDiff dir1 dir2"

Il répertorie non seulement les fichiers qui sont différents entre les répertoires, mais vous permet également d'inspecter / modifier avec vimdiff les fichiers qui sont différents.


11

Insatisfait de toutes les réponses, car la plupart d'entre elles fonctionnent très lentement et produisent une sortie inutilement longue pour les grands répertoires, j'ai écrit mon propre script Python pour comparer deux dossiers.

Contrairement à de nombreuses autres solutions, il ne compare pas le contenu des fichiers. De plus, il ne va pas dans les sous-répertoires qui manquent dans un autre répertoire. La sortie est donc assez concise et le script fonctionne rapidement.

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

Exemple d'utilisation:

user@laptop:~$ python3 compare_dirs.py dir1/ dir2/
DIR  dir1/out/flavor-domino removed
DIR  dir2/out/flavor-maxim2 added
DIR  dir1/target/vendor/flavor-domino removed
DIR  dir2/target/vendor/flavor-maxim2 added
FILE dir1/tmp/.kconfig-flavor_domino removed
FILE dir2/tmp/.kconfig-flavor_maxim2 added
DIR  dir2/tools/tools/LiveSuit_For_Linux64 added

Ou si vous souhaitez voir uniquement les fichiers du premier répertoire:

user@laptop:~$ python3 compare_dirs.py dir2/ dir1/ | grep dir1
DIR  dir1/out/flavor-domino added
DIR  dir1/target/vendor/flavor-domino added
FILE dir1/tmp/.kconfig-flavor_domino added

PS Si vous avez besoin de comparer les tailles de fichiers et les hachages de fichiers pour d'éventuelles modifications, j'ai publié un script mis à jour ici: https://gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779


Script assez simple qui fait exactement ce que je voulais: vérifier une copie en bloc: +1 de moi. (besoin de convertir en python2 cependant) Astuce: l'utilisation d'ensembles pourrait rendre la partie diff plus simple.
Jason Morgan

6

Une autre approche (peut-être plus rapide pour les grands répertoires):

$ find dir1 | sed 's,^[^/]*/,,' | sort > dir1.txt && find dir2 | sed 's,^[^/]*/,,' | sort > dir2.txt
$ diff dir1.txt dir2.txt

La sedcommande supprime le premier composant du répertoire grâce à la publication d'Erik )


1
Je crois que cette méthode est plus simple (toujours en utilisant finddonc un commentaire et non une réponse séparée): cd dir2; find . -exec [ -e ../dir1/{} ] \; -o -print 2>/dev/null Cela imprimera les fichiers présents dans dir2 mais pas présents dans dir1.
Alexander Amelkin

5

C'est un peu tard mais ça peut aider quelqu'un. Je ne sais pas si diff ou rsync crachent uniquement des noms de fichiers dans un format nu comme celui-ci. Merci à plhn d'avoir donné cette belle solution que j'ai développée ci-dessous.

Si vous ne voulez que les noms de fichiers, il est donc facile de copier simplement les fichiers dont vous avez besoin dans un format propre, vous pouvez utiliser la commande find.

comm -23 <(find dir1 | sed 's/dir1/\//'| sort) <(find dir2 | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

Cela suppose que dir1 et dir2 se trouvent dans le même dossier parent. sed supprime simplement le dossier parent afin que vous puissiez comparer les pommes avec les pommes. Le dernier sed remet juste le nom dir1.

Si vous voulez juste des fichiers:

comm -23 <(find dir1 -type f | sed 's/dir1/\//'| sort) <(find dir2 -type f | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

De même pour les répertoires:

comm -23 <(find dir1 -type d | sed 's/dir1/\//'| sort) <(find dir2 -type d | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'

1
Notez que vous pouvez faire cdavant au findlieu d'avoir à utiliser sed, par exemple: comm -23 <(cd dir1 || exit; find -type f | sort) <(cd dir2 || exit; find -type f | sort). (Les exits sont là pour empêcher findd'utiliser le répertoire courant devrait cdéchouer.)
phk

Notez également que votre solution peut échouer lorsque des fichiers avec certains caractères spéciaux sont présents, si vous avez une version très récente de commavec des supports -z(fournie avec git.savannah.gnu.org/cgit/coreutils.git/commit/… ), vous pouvez le faire comm -23 -z <(cd dir1 && find -type f -print0 | sort -z) <(cd dir2 && find -type f -print0 | sort -z). (En attendant, j'ai aussi compris que les exits pouvaient être remplacés.)
phk

5

La réponse acceptée répertorie également les fichiers qui existent dans les deux répertoires, mais dont le contenu est différent. Pour répertorier UNIQUEMENT les fichiers qui existent dans dir1, vous pouvez utiliser:

diff -r dir1 dir2 | grep 'Only in' | grep dir1 | awk '{print $4}' > difference1.txt

Explication:

  • diff -r dir1 dir2: comparer
  • grep 'Only in': récupère les lignes qui contiennent 'Only in'
  • grep dir1: récupère les lignes qui contiennent dir

5

Cette réponse optimise l'une des suggestions de @ Adail-Junior en ajoutant l' -Doption, qui est utile lorsqu'aucun des répertoires comparés n'est un référentiel git:

git diff -D --no-index dir1/ dir2/

Si vous utilisez, -Dvous ne verrez pas de comparaisons avec /dev/null: text Binary files a/whatever and /dev/null differ


Était très utile pour comparer deux répertoires, vous voyez instantanément les différences entre les fichiers. Bien sûr, fonctionne mieux sur les fichiers avec du contenu texte.
Erich Kuester

1

Une façon simplifiée de comparer 2 répertoires à l'aide de la commande DIFF

diff filename.1 filename.2> filename.dat >> Entrée

ouvrir filename.dat une fois l'exécution terminée

et vous verrez: Uniquement dans filename.1: filename.2 Uniquement dans: directory_name: name_of_file1 Uniquement dans: directory_Name: name_of_file2


Pourquoi devez-vous exporter vers un fichier .dat?
Vishnu NK

1

Ceci est le script bash pour imprimer les commandes de synchronisation de deux répertoires

dir1=/tmp/path_to_dir1
dir2=/tmp/path_to_dir2
diff -rq $dir1 $dir2 | sed -e "s|Only in $dir2\(.*\): \(.*\)|cp -r $dir2\1/\2 $dir1\1|" |  sed -e "s|Only in $dir1\(.*\): \(.*\)|cp -r $dir1\1/\2 $dir2\1|" 

0

GNU greppeut inverser la recherche avec l'option -v. Cela rend le grepsignalement des lignes qui ne correspondent pas. Par cela, vous pouvez supprimer les fichiers dir2de la liste des fichiers dir1.

grep -v -F -x -f <(find dir2 -type f -printf '%P\n') <(find dir1 -type f -printf '%P\n')

Les options -F -xindiquent grepd'effectuer une recherche de chaîne sur toute la ligne.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.