Ich versuche, die Dateien in einem Verzeichnis zu finden, aber nicht im anderen. Ich habe versucht, diesen Befehl zu verwenden:
diff -q dir1 dir2
Das Problem mit dem obigen Befehl, dass er sowohl die Dateien in dir1
aber nicht in dir2
findet, als auch die Dateien in dir2
aber nicht in dir1
,
Ich versuche, die Dateien in dir1
zu finden, aber nicht nur in dir2
.
Hier ist ein kleiner Ausschnitt dessen, wie meine Daten aussehen
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
Eine andere Frage ist, wie ich die Dateien in dir1
finden kann, aber nicht in dir2
oder dir3
in einem einzigen Befehl.
diff -r dir1 dir2 | grep dir1 | awk '{print $4}' > difference1.txt
Erklärung:
diff -r dir1 dir2
zeigt an, welche Dateien nur in dir1 und diejenigen nur in dir2 sind, und auch die Änderungen der Dateien, die in beiden Verzeichnissen vorhanden sind.
diff -r dir1 dir2 | grep dir1
zeigt, welche Dateien sich nur in dir1 befinden
awk
, um nur den Dateinamen zu drucken.
Dies sollte die Arbeit erledigen:
diff -rq dir1 dir2
Optionen erklärt (via diff (1) manpage ):
-r
- Rekursiv alle gefundenen Unterverzeichnisse vergleichen.-q
- Nur ausgeben, wenn sich Dateien unterscheiden.comm -23 <(ls dir1 |sort) <(ls dir2|sort)
Mit diesem Befehl erhalten Sie Dateien, die sich in dir1 und nicht in dir2 befinden.
Über <( )
sign können Sie es als "Prozessersetzung" googeln.
Eine gute Möglichkeit für diesen Vergleich ist die Verwendung von find
mit md5sum
und dann einer diff
.
Beispiel:
Verwenden Sie find
, um alle Dateien im Verzeichnis aufzulisten, berechnen Sie dann den md5-Hash für jede Datei und leiten Sie ihn an eine Datei weiter:
find /dir1/ -type f -exec md5sum {} \; > dir1.txt
Führen Sie dasselbe Verfahren für ein anderes Verzeichnis aus:
find /dir2/ -type f -exec md5sum {} \; > dir2.txt
Vergleichen Sie dann das Ergebnis zwei Dateien mit "diff":
diff dir1.txt dir2.txt
Diese Strategie ist sehr nützlich, wenn sich die beiden zu vergleichenden Verzeichnisse nicht auf derselben Maschine befinden und Sie sicherstellen müssen, dass die Dateien in beiden Verzeichnissen gleich sind.
Eine andere gute Möglichkeit, den Job zu erledigen, ist die Verwendung von git
git diff --no-index dir1/ dir2/
Freundliche Grüße!
Meld ( http://meldmerge.org/ ) ist ein hervorragender Job beim Vergleichen von Verzeichnissen und den darin enthaltenen Dateien.
das DirDiff Plugin von vim ist ein weiteres sehr nützliches Werkzeug zum Vergleichen von Verzeichnissen.
vim -c "DirDiff dir1 dir2"
Es listet nicht nur auf, welche Dateien zwischen den Verzeichnissen unterschiedlich sind, sondern ermöglicht Ihnen auch, mit vimdiff zu prüfen, welche Dateien unterschiedlich sind.
Unzufrieden mit allen Antworten, da die meisten von ihnen sehr langsam arbeiten und unnötig lange Ausgaben für große Verzeichnisse erzeugen, schrieb ich mein eigenes Python-Skript, um zwei Ordner zu vergleichen.
Im Gegensatz zu vielen anderen Lösungen wird der Inhalt der Dateien nicht verglichen. Es geht auch nicht in Unterverzeichnisse, die in einem anderen Verzeichnis fehlen. Die Ausgabe ist also recht knapp und das Skript funktioniert schnell.
#!/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])
Verwendungsbeispiel:
[email protected]:~$ 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
Oder wenn Sie nur Dateien aus dem ersten Verzeichnis anzeigen möchten:
[email protected]:~$ 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. Wenn Sie die Dateigrößen und Datei-Hashwerte für mögliche Änderungen vergleichen müssen, habe ich hier ein aktualisiertes Skript veröffentlicht: https://Gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779
Ein weiterer Ansatz (möglicherweise schneller für große Verzeichnisse):
$ find dir1 | sed 's,^[^/]*/,,' | sort > dir1.txt && find dir2 | sed 's,^[^/]*/,,' | sort > dir2.txt
$ diff dir1.txt dir2.txt
Der Befehl sed
entfernt die erste Verzeichniskomponente dank Eriks Beitrag )
Dies ist etwas spät, kann aber jemandem helfen. Nicht sicher, ob diff oder rsync nur Dateinamen in einem bloßen Format wie diesem ausspuckt. Danke an plhn für die schöne Lösung, auf die ich unten eingegangen bin.
Wenn Sie nur die Dateinamen benötigen, um die gewünschten Dateien einfach in einem sauberen Format zu kopieren, können Sie den Befehl find verwenden.
comm -23 <(find dir1 | sed 's/dir1/\//'| sort) <(find dir2 | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'
Dies setzt voraus, dass sich dir1 und dir2 im selben übergeordneten Ordner befinden. sed entfernt nur den übergeordneten Ordner, damit Sie Äpfel mit Äpfeln vergleichen können. Der letzte sed setzt nur den dir1-Namen zurück.
Wenn Sie nur Dateien wünschen:
comm -23 <(find dir1 -type f | sed 's/dir1/\//'| sort) <(find dir2 -type f | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'
Ähnlich für Verzeichnisse:
comm -23 <(find dir1 -type d | sed 's/dir1/\//'| sort) <(find dir2 -type d | sed 's/dir2/\//'| sort) | sed 's/^\//dir1/'
Die akzeptierte Antwort listet auch die Dateien auf, die in beiden Verzeichnissen vorhanden sind, aber unterschiedlichen Inhalt haben. Um NUR die in dir1 vorhandenen Dateien aufzulisten, können Sie Folgendes verwenden:
diff -r dir1 dir2 | grep 'Only in' | grep dir1 | awk '{print $4}' > difference1.txt
Erläuterung:
Dies ist das Bash-Skript zum Drucken von Befehlen zum Synchronisieren zweier Verzeichnisse
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|"
Diese Antwort optimiert einen der Vorschläge von @ Adail-Junior durch Hinzufügen der Option -D
, was hilfreich ist, wenn keines der zu vergleichenden Verzeichnisse git-Repositorys sind:
git diff -D --no-index dir1/ dir2/
Wenn Sie -D
verwenden, werden keine Vergleiche mit /dev/null
: text
Binary files a/whatever and /dev/null differ
angezeigt.
GNU grep
kann die Suche mit der Option -v
umkehren. Dies führt dazu, dass grep
die Zeilen meldet, die nicht übereinstimmen. Auf diese Weise können Sie die Dateien in dir2
aus der Liste der Dateien in dir1
entfernen.
grep -v -F -x -f <(find dir2 -type f -printf '%P\n') <(find dir1 -type f -printf '%P\n')
Die Optionen -F -x
weisen grep
an, eine Zeichenfolgesuche in der gesamten Zeile durchzuführen.
Eine vereinfachte Methode zum Vergleichen von 2 Verzeichnissen mithilfe des Befehls DIFF
diff Dateiname.1 Dateiname.2> Dateiname.dat >> Eingeben
Öffnen Sie Dateiname.dat, nachdem der Lauf abgeschlossen ist
und Sie sehen: Nur in Dateiname.1: Dateiname.2 Nur in: Verzeichnisname: Dateiname1 Nur in: Verzeichnisname: Dateiname2