Différence entre deux répertoires sous Linux
Je suis en train de trouver les fichiers 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 qu'il trouve à la fois les fichiers dans dir1
, mais pas dans dir2
ainsi que les fichiers dans dir2
, mais pas dans dir1
,
Je suis en train de trouver les fichiers dans dir1
, mais pas dans dir2
seulement.
Voici un petit échantillon de mes données
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 dans mon esprit est Comment puis-je trouver les fichiers dans dir1
mais pas dans dir2
ou dir3
en une seule commande?
14 réponses
diff -r dir1 dir2 | grep dir1 | awk '{print $4}' > difference1.txt
Explication:
diff -r dir1 dir2
affiche les fichiers sont seulement dans dir1 et ceux-là seulement dans dir2 et aussi les changements des fichiers présents dans les répertoires, le cas échéant.diff -r dir1 dir2 | grep dir1
affiche les fichiers sont seulement dans dir1awk
pour imprimer uniquement le nom de fichier.
Cela devrait faire le travail:
diff -rq dir1 dir2
Options expliquées (via diff (1) page de manuel):
-
-r
- comparer récursivement tous les sous-répertoires trouvés. -
-q
- affiche uniquement si les fichiers diffèrent.
comm -23 <(ls dir1 |sort) <(ls dir2|sort)
Cette commande vous donnera les fichiers qui sont dans dir1 et Pas dans dir2.
À propos du signe <( )
, vous pouvez le google en tant que 'substitution de processus'.
Un bon moyen de faire cette comparaison est d'utiliser find
avec md5sum
, puis diff
.
Exemple:
Utilisez find
pour lister 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
Faites la même procédure dans 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 sont pas dans la même machine et vous devez vous assurer que 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/
Cordialement!
Meld ( http://meldmerge.org / ) fait un excellent travail à comparer les répertoires et les fichiers à l'intérieur.
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 aussi vous permet d'inspecter/modifier avec vimdiff les fichiers qui sont différents.
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 commande sed
supprime le premier composant de répertoire grâce au post D'Erik )
, C'est un peu tard, mais peut aider quelqu'un. Je ne sais pas si diff ou rsync crachent juste des noms de fichiers dans un format nu comme celui-ci. Merci à plhn pour avoir donné cette belle solution que j'ai développée ci-dessous.
Si vous voulez juste les noms de fichiers pour qu'il soit facile de simplement copier 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 sont tous deux 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/'
La réponse acceptée listera également les fichiers qui existent dans les deux répertoires, mais ont un contenu différent. Pour lister 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 'Seulement': obtenir des lignes qui contiennent "Seulement en'
- grep dir1: récupère les lignes qui contiennent dir
Insatisfait de toutes les réponses, puisque 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 à beaucoup d'autres solutions, il ne compare pas le contenu des fichiers. En outre, il ne va pas dans les sous-répertoires qui manquent dans un autre répertoire. Donc la sortie est très concis 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 voulez voir uniquement les fichiers depuis le 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
P.S. si vous avez besoin de comparer les tailles de fichiers et les hachages de fichiers pour des changements potentiels, j'ai publié un script mis à jour ici: https://gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779
Une façon simplifiée de comparer 2 répertoires à L'aide de la commande DIFF
Nom du fichier Diff.1 nom de fichier.2 > nom de fichier.dat > > entrez
Ouvrir le nom de fichier.dat après la fin de l'exécution
Et vous verrez: Uniquement dans le nom de fichier.1: Nom du fichier.2 Seulement dans: directory_name: name_of_file1 Seulement dans: directory_Name: name_of_file2
Kdiff3 a une belle interface de diff pour les fichiers et les répertoires.
Vérifier l'URL: http://kdiff3.sourceforge.net
Cela fonctionne sous Windows et Linux.
GNU grep
peut inverser la recherche avec l'option -v
. Cela fait que grep
signale les lignes qui ne correspondent pas. Vous pouvez ainsi supprimer les fichiers de dir2
de la liste des fichiers de dir1
.
grep -v -F -x -f <(find dir2 -type f -printf '%P\n') <(find dir1 -type f -printf '%P\n')
Les options -F -x
indiquent à grep
d'effectuer une recherche de chaîne sur toute la ligne.
C'est le script bash pour imprimer des commandes pour synchroniser 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|"