107. Dubletten (Duobletten) mit Batch finden

Einleitung

Das Finden von Datei-Duobletten bzw. Dateiduplikaten mit einer Batch scheint zu einer der schweren Aufgaben zu gehören, da im Internet bisher keine validen Auskünfte und der Verweis, dass Batches nicht zum Aufifinden von Dateiduplikaten geeignet seien, selbst bei den etwas professionellen Seiten zur Standardantwort gehören. Das ist eine mutige Aussage, wenn man bedenkt, dass der Sternenhimmelstuermer gerade 14 Zeilen mit Grundbefehlen für diese Aufgabe brauchte.

Der Sternenhimmelstuermer arbeitet wieder auf der Metaebene und zeigt einen validen Lösungsweg, den jeder Batchschreiber nach Bedarf anpassen kann - der Lösungsweg steht im Mittelpunkt und nicht die Batch per se. Bereits in einer der letzten Abhandlung über die Bearbeitung von Tabellen lieferte der Sternenhimmelstuermer den kompletten Befehlssatz in kleinen Abwandlungen. Diese Abhandlung war eher für Anfänger gedacht, obwohl das zusammenfügen von Tabellen nebeneinander in einem Dokument eine bereits herausragende Leistung ist...

Der Sternenhimmelstuermer wird diesmal alles ein wenig kürzer erklären. Wer nicht folgen kann, lese bitte die o. a. Abhandlung...

Batch

Dateiname: doubletten.bat
Inhalt:

SET /p original=Geben Sie den Pfad zum Originalverzeichnis ein
SET /p vergleich=Geben Sie den Pfad zum Verzeichnis mit den Dubletten ein
set /p Dateiendung=Geben sie die Dateiendung ein
chcp 28591 > NUL
for %%i in ("%original%\*.%Dateiendung%") do @echo %%~ni ^:%%~zi ^:%%i >>org.log
chcp 28591 > NUL
for %%i in ("%vergleich%\*.%Dateiendung%") do @echo %%~ni ^:%%~zi ^:%%i >>verg.log
chcp 28591 > NUL
FOR /F "tokens=1,2,3* delims=:"  %%i  IN (org.log) DO echo %%i %%j %%k^:%%l  >>ergebnis_%%j.log
chcp 28591 > NUL
FOR /F "tokens=1,2,3* delims=:"  %%i  IN (verg.log) DO echo %%i %%j %%k^:%%l >>ergebnis_%%j.log
for /f "delims=" %%a in ('dir /b /a-d ergebnis_*.log') do more +1 "%%a">neu_%%a
copy neu_*.log double.txt
del *.log


Die Erklärung der Batch in Schritten und eine Variante der Batch mit zehn Zeilen für ein Verzeichnis mit Unterverzeichnissen kommen nach Erklärung der Funktionsweise.
Für Profis ist die Abhandlung hier bereits beendet...

Funktionsweise der Batch mit einfachen Worten kurz erklärt:

Als erstes werden drei Eingaben erwartet:

1. Der Pfad zum Verzeichnis, wo die Originaldateien liegen
2. Der Pfad im Verzeichnis, mit dem die Dateien verglichen werden sollen
3. Die Dateiendung ohne Punkt:  MP3, Doc, Docx, PDF, JPG - ist so ziemlich egal - es sei denn es sind log Logdateien oder txt Textdateien

erster Arbeitsschritt

Dann geht es schon los! im ersten Arbeitsschritt werden die zwei Verzeichnisse  nach Dateien mit der eingegebenen Dateiendung überprüft .  Wird eine Datei gefunden, so wird  der Dateiname, die Dateigröße und der komplette Dateipfad  in eine  Logdatei geschrieben. Es existieren dann zwei Logdateien (org.log - für die Dateien im Verzeichnis mit den Originaldateien und verg.log für  die Dateien im Vergleichsverzeichnis).


zweiter Arbeitsschritt


Im nächsten Arbeitsschritt wird jede Zeile der beiden Dateien in ein Dokument mit dem Namen ergebnis_%%j.log übergeben. %%j ist in diesem Fall die Dateigröße, die Bestandteil  des ergebnis_%%j.log ist.  Dadurch, dass ein  >> doppelter Ausgabepfeil existiert, wird für jede Zeile eine einzelne Logdatei geschaffen. Die Dateigröße wird übrigens in Bytes ausgegeben und ist fast so individuell wie ein Hash-Wert...

Nach dem ersten For Befehl sind also vom org.log sämtliche Zeilen in jeweils einer Datei mit dem Größenwert im Ergebnis.

Nach dem zweiten Durchgang des For - Befehls vom verg.log kommen nun neue Ergebnis- Log-Dateien dazu, wenn Sie nicht im Originalverzeichnis waren. Das ist unwichtig, aber zum Verständnis absolut notwendig.

Der folgende Satz ist überwichtig zum Verständnis:  Durch den doppelten Ausgabepfeil wird bei einer Dublette mit derselben Dateigröße  die Ausgabe in die bereits bestehende Datei  des  Ergebnis-Größe-Log  als zweite Zeile ergänzt.  Da Dateiendung und Größe gleich sind, handelt es sich mit an Sicherheit grenzender Wahrscheinlichkeit um eine Dublette  - insbesonder bei Dateien über 5 KB ist die Wahrscheinlichkeit  einer Verwechslung verschwindend gering...

Zwischenstand

Wir haben nun eine richtig große Anzahl mit Ergebnis-Größe-Log-Dateien mit einer Zeile und je nach Anzahl der Dubletten auch Ergebnis-Größe-Log-Dateien mit zwei oder mehr Zeilen, von denen wir mit großer Sicherheit davon ausgehen können, dass es sich beim Inhalt der Zeile um eine Dublette handelt (zur Erinnerung: in jeder Zeile stand Dateiname, Größe und Dateipfad!


dritter Arbeitsschritt

Der nächste Arbeitsschritt ist ein wenig trickreich: Wir entfernen aus jeder Ergebnis-Größe-Log-Datei die erste Zeile mit dem more Befehl. Wozu ist das gut? Wir bekommen nun jede Menge "neu_%%a"- Dateien, wobei %%a  nur eine andere Version der  Ergebnis-Größe-Log-Datei ist - nur eben um die erste Zeile durch den More-Befehl  reduziert.

Dadurch entstehen eine Menge Dateien, die 0 kb groß sind und somit eben auch keinen Inhalt haben (im wahrsten Sinne Hüllen ohne Seele...). Aber unser Dublettendateien hatten ja mindestens zwei Zeilen. Das ist das wichtige: Die zwei Zeilen werden auf eine Zeile reduziert und Hurra: wir haben das Zeil erreicht: Dateien, in denen nur unsere Dubletten in einfacher Ausführung stehen! In einer Zeile mit den drei Angaben Dateiname , Größe und Dateipfad.


vierter Arbeitsabschritt

Die Zeilen in den einzelnen Dateien müssen wir nur noch zusammenführen - der Sternenhimmelstuermer bevorzugt hier einen einfachen copy - Befehl: Mit der Anweisung allen Inhalt der Dateien neu_*.log  zusammenzufassen (in double.txt) werden alle Zeilen zusammengeführt. In den Nullbyte Dateien ist kein Inhalt - also auch keine Zeile die kopiert wird.

Im letzten Schritt werden die Log-Dateien mit del *.log zerstört. Hey, für die Nullbyte-Dateien hätte man auch forfiles einsetzen können, ein sinnentleertes Zwischenspiel für Batchschreiber, die gerne noch eine Zeile mehr schreiben wollen.


Im  double.txt steht dann das Ergebnis, also sämtliche Zeilen mit übereinstimmender Dateigröße und Endung. In der Zeile finden Sie Dateiname Dateigröße und Dateipfad - alles durch Leerzeichen sauber getrennt.
Das Löschen der Dubletten können Sie dann selbstständig durchführen. Mit der Vorlage double.txt echt easy!

Die Batchschreiber, die diesen Weg nutzen werden, sind für die Löschroutine fit genug und Anfänger will der Sternenhimmelstuermer nicht unglücklich machen, weil Sie wichtige Dateien durch unbedarftes Handeln evtl. zerschießen. Hier ist der Sternenhimmelstuermer eigen - es gibt genug Tools, die Dubletten finden, anzeigen und löschen. Gleichwohl werden Fortgeschrittene diesen einfachen Lösungsweg schätzen.



Batch (Wiederholung des Codes)

Dateiname: doubletten.bat
Inhalt:

SET /p original=Geben Sie den Pfad zum Originalverzeichnis ein
SET /p vergleich=Geben Sie den Pfad zum Verzeichnis mit den Dubletten ein
set /p Dateiendung=Geben sie die Dateiendung ein
chcp 28591 > NUL
for %%i in ("%original%\*.%Dateiendung%") do @echo %%~ni ^:%%~zi ^:%%i >>org.log
chcp 28591 > NUL
for %%i in ("%vergleich%\*.%Dateiendung%") do @echo %%~ni ^:%%~zi ^:%%i >>verg.log
chcp 28591 > NUL
FOR /F "tokens=1,2,3* delims=:"  %%i  IN (org.log) DO echo %%i %%j %%k^:%%l  >>ergebnis_%%j.log
chcp 28591 > NUL
FOR /F "tokens=1,2,3* delims=:"  %%i  IN (verg.log) DO echo %%i %%j %%k^:%%l >>ergebnis_%%j.log
for /f "delims=" %%a in ('dir /b /a-d ergebnis_*.log') do more +1 "%%a">neu_%%a
copy neu_*.log double.txt
del *.log


Einfach blau-grünen Texbereich in eine Batch (*.bat) kopieren, in einem beliebigen leeren Ordner platzieren und mit Doppelklick starten:  sämtliche relevanten und erstellten  Dateien für die Bearbeitung liegen relativ, also im selben Ordner der Batch vor...Die Batch ist harmlos - nichts wird im Wesen der Originale berührt...

Wer ein wenig wissen will, wie es so zwischenzeitlich läuft, sollte einfach den Befehl  del *.log löschen - dann können Sie sich die ganzen Logdateien einmal in Ruhe anschauen - das hilft ungemein!

Erweiterungsmöglichkeiten in der Anwendung:

Tauschen Sie im ergebnis_%%j.log durch ergebnis_%%i in den zwei For-Befehlen aus, so wird die Prüfung über den Dateinamen gemacht. Für den Sternenhimmelstuermer ist die Prüfung über die Dateigröße wesentlich sicherer, da dort keine Leerzeichen, ü. ä oder ä das Ergebnis ungünstig beeinflussen Können. Wie gesagt, bei zwei Kriterien reicht die Dateigröße (andere Kriterium war Dateiendung - nur mal so zur Erinnerung).

Eine andere Variante wäre es beim Vergleich ergebnis_%%i_%%j zu verwenden, um nach Dateinamen und Größe die Dubletten zu suchen...Dann müssen Sie die beiden For-Befehle und den kombinierten For Dir-Befehl entsprechend anpassen. Das sind alles marginale Veränderungen.

Trauen Sie dem Ergebnis nicht. Dann können Sie den Ergebnis.txt wieder zerlegen und mit einem For Befehl mit findstr im ergebnis.txt gerne einen Abgleich im orig.log starten...Die Batch kann beliebig aufgebläht werden...

Sie können die Batch übrigens auf sieben Zeilen reduzieren: Einfach eine Dateiliste von Verzeichnissen und Unterverzeichnissen mit Dateinamen Größe und Dateipfad erstellen und ab dem For - Befehl ergebnis_%%j.log, der dann nur einmal für die Liste verwendet wird, ist alles wieder dasselbe.  Wie das geht, wird noch im Abschnitt Variante der Suche in einem Verzeichnis mit Unterordnern erklärt.


Besonderheiten für Fortgeschrittene kurz und knapp


SET /p original=Geben Sie den Pfad zum Originalverzeichnis ein
SET /p vergleich=Geben Sie den Pfad zum Verzeichnis mit den Dubletten ein
set /p Dateiendung=Geben sie die Dateiendung ein

Diese drei Zeilen mach nur die Eingaben der User zu variablen, also nichts außergewöhnliches. Der Name der Variable steht dann vor dem Gleichheitszeichen. Später muss dieser zwischen zwei Prozentzeichen in einer Batch verwendet werden..

chcp 28591 > NUL

Dieser Befehl ist für ä,ü,ö usw zuständig - ein typisch deutsches Problem. Die Batch funktioniert zwar auch ohne diese Befehle - aber es kommen im Textdokument unleserliche Dokument heraus, was auch für die Weiterbearbeitung nicht so günstig ist..
Der Befehl kommt vor jedem For-Befehl und wird deshalb in der kommenden Beschreibung mal unterschlagen...

for %%i in ("%original%\*.%Dateiendung%") do @echo %%~ni ^:%%~zi ^:%%i >>org.log


Im Pfad zum Originalverzeichnis %original%\ wird  jede Datei  *.  mit der %Dateiendung%  gesucht und von dieser  wird (do) von einer gefundenen Datei folgende Eigenschaften ausgegeben  (@echo) :  Dateiname mit Endung (%%~ni ), danach ein Doppelpunkt (^:), danach die Dateigröße in Bytes ( %%~zi ), danach wieder ein Doppelpunkt (^:) der komplette Dateipfad und am Ende der komplette Dateipfad (%%i ).

Wozu diese Doppelpunktarie?: Wir bauen uns eine kleine Tabelle mit Doppelpunkten als Seperatoren! Das sind die Delims im übernächsten For-Befehl, der gleich zm besseren Verständnis nochmal erklärt wird. Einige aufgeweckte User müssten nun aufschreien: Das ist ganz schön dumm, wenn man einen Doppelpunkt als Seperator benutzt, wo in einem Dateipfad in der Regel immer ein Doppelpunkt steht - wie z. B. im Pfad  C:\blabla\pfad

Richtig - aber wenn man das weiß, kann man das auch korregieren:

FOR /F "tokens=1,2,3* delims=:"  %%i  IN (org.log) DO echo %%i %%j %%k^:%%l  >>ergebnis_%%j.log

Der Sternenhimmelstuermer gibt hier 3 und Folgebestandteile als Tokens ein und den Doppelpunkt als Seperator bzw. Delims in der For-Befehlssprache!

Der Knackpunkt des For - Befehls ist %%k^:%%l   %%k ist dabei, was vor dem Doppelpunkt steht, also z. B. das C bei C:\blabla\pfad

Danach wird wieder künstlich ein Doppelpunkt eingefügt. Dazu brauchen wir wieder das Sonderzeichen  , weil sonst der Doppelpunkt nicht als Schriftzeichen interpretiert wird.

Wir haben nun C: - mühsam nährt sich das Eichhörnchen.

Deshalb brauchen wir %%l , welches dem Rest nach dem Doppelpunkt, also  \blabla\pfad entspricht und unmittelbar nach dem Doppelpunkt eingefügt wird:

Der komplette Pfad ist also in dieser Zeile C:\blabla\pfad

Die Ganze Zeile wird dann in ergebnis_%%j.log geschrieben. Bei einer Dublette stehen dann wieder zwei Zeilen in den Ergebnis_Größe_Logs!   

for /f "delims=" %%a in ('dir /b /a-d ergebnis_*.log') do more +1 "%%a">neu_%%a

Tja, hier werden dann sämtliche Dateien mit Namen Ergebnis-Größe-log bearbeitet und  die erste Zeile übersprungen und der Rest ausgelesen und als %%a alle Zeilen ausgegeben. Das Ganze in einem neu_%%a, was dem  Namen und der Dateiendung also neu_Größe.log entspricht. Es gibt hier übrigens keine Delims in den Zeilen (also Separatoren), was betont werden muss, damit immer ganze Zeilen gemeint sind.

Ist wirklich ein wenig fies, da das nicht sofort verständlich ist.

copy neu_*.log double.txt

Alle (*) Dateien werden nun in eine Datentextdokument kopiert. Wieso denn nun alle? Richtig, die Null-Byte Dateien, bei durch Verwendung des more +1 entstanden sind haben keinen Inhalt und beeinflussen damit auch nicht das Ergebnis...

del *.log

Am Ende werden sämtliche Logdateien mit dem Del-Befehl zerstört. Die Nullbyte-Dateien natürlich auch - sind zwar Hüllen ohne Seele, nehmen jedoch noch Cluster in Anspruch - eine etwas geschummelte Null (ist aber irgendwo klar, denn allein der Dateiname hat ja einen gewissen Speicherbedarf).

Variante der Suche in einem Verzeichnis mit Unterordnern


beliebigername.bat

SET /p verzeichnis=Geben Sie den Pfad zum verzeichnis ein
set /p Dateiendung=Geben sie die Dateiendung ein
chcp 28591 > NUL
for /f "delims=" %%i in ('dir %verzeichnis%\*.%Dateiendung% /s /b /a-d') do @echo %%~ni ^:%%~zi ^:%%i >>org.log
chcp 28591 > NUL
FOR /F "tokens=1,2,3* delims=:"  %%i  IN (org.log) DO echo %%i %%j %%k^:%%l  >>ergebnis_%%j.log
chcp 28591 > NUL
for /f "delims=" %%a in ('dir /b /a-d ergebnis_*.log') do more +1 "%%a">neu_%%a
copy neu_*.log double.txt
del *.log

Dabei muss vor jedem For - Befehl die Anweisung zur Beibehaltung von ü,ö, ä eingegeben werden (chcp 28591 > NUL). Ein ziemlich deutsches Problem, daher mal wieder vergessen

Beim Einstieg dieser Batch muss ein DOS-Konformer Pfad gewählt werden!!!

Was heißt das? Bei der ersten Eingabe des Pfades zum Ordner oder dem Laufwerk in der Hierarchie darf es keine Namen mit Leerzeichen im Pfad geben. Außerdem nicht gegen die Regel mehr als sechs Buchstaben verstoßen. Hintergrund: Beim Einstieg in den Dir Befehl sind wir durch den For-Befehl im DOS-Modus. Aus z. B. dem Ordnernamen: Manfred Sternenhimmelstuermer wird im DOS-Modus: Manfre~1
Hat die Batch den Einstieg gefunden, dann funktioniert der Rest auch. Einige Nutzer geben Vornamen, Leerzeichen und Benutzername als Benutzerkontonamen ein - der Sternenhimmelstuermer übrigens auch - um sich immer daran zu erinnern Batches konform zu schreiben. Typische Fehlermeldung: Der Pfad konnte nicht gefunden werden...Probieren Sie es ruhig aus - wie gesagt: mehr als eine Fehlermeldung kann nicht passieren...

Diese Batch bezieht sich auf die Suche in einem Verzeichnis mit Unterordnern oder per se in einem ganzen Laufwerk. Hier wird nur eine Dateiliste mit Namen Größe und Dateipfad gebildet. Der Rest ist so ziemlich gleich. Die entscheidende Zeile zur Darstellung der eben genannten Werte in Tabellenform in dem Textdokument wird nochmal erklärt:

for /f "delims=" %%i in ('dir %verzeichnis%\*.%Dateiendung% /s /b /a-d') do @echo %%~ni ^:%%~zi ^:%%i >>org.log

Viele User können leider keine passenden Tabellen mit Angabe von Name:Größe:Dateiname erstellen - insbesondere nicht von Unterverzeichnissen.

Es bietet sich eine Hybridform mit Arbeitsteilung an: dir bis * ist der Pfad zu beliebigen Dateien - *.%Dateiendung% : * sind also die Dateien mit .%Dateiendung% . Zur Erinnerung %Dateiendung% ist die Variable für die Dateiendung, die der User am Anfang eingab: Also z. B. PDF

Ab /s beginnen die Parameter des Dir Befehls : /s - Unterordner werden durchsucht /b blanke Dateinamen abgefragt /a-d schauen Sie bitte in der cmd unter dir /? Returntaste in der Windowshilfe der CMD nach. Ab do @echo sind wir wieder bei anteilen der For-Schleife. %%i  ist jeweils die vom dir-Befehl gefundene Datei mit der Dateiendung PDF in unserem Pseudobeispiel. Die Abfragetechnik %%~ni ^:%%~zi ^:%%i wurde bereits erklärt. In der Windowshilfe über for /? sind die übrigens auch nochmal dürftig erklärt.
 

Fazit

Die Sternenhimmelstuermerseite hat wieder als Meta-Seite bewiesen, dass mit ein wenig Spieltrieb und Fantasie ein Lösungsweg zur Suche von Dubletten möglich ist - alles mit Grundbefehlen, die in der Abhandlung über den Umgang mit CSV-Dateien sehr ausführlich beschrieben wurden.

Damit ist das Thema Dubletten auch abgehakt. Es gibt genug Tools dafür - es freut aber den Sternenhimmelstuermer in Abständen wider den "Experten" zu beweisen, dass mit Batches alles möglich ist - und das mit zehn  Befehlszeilen... oder sogar in einer einfacheren Variation mit sieben Zeilen

Unumstritten hat die Sternenhimmelstuermer im Batchbereich mit die progessivste Webseite mit veröffentlichten Batches eines Amateurs mit Erklärungen derselben. Diese Abhandlungen könnten Sie interessieren:


Speicherfresserbatch Dokumente nach Größe suchen
Archivbatch Dokumente nach Jahren in Ordner sortieren
Windowshilfe Windowshilfe ausdrucken
switchbatch Zwischen Registrywerten switchen
Lernbatch Eine selbst lernende Batch
Bearbeitung von Tabellen eine Batch zum zusammenführen von Tabellen nebeneinander

Excel dasselbe: Die Projekte der Sternenhimmelstuermerseite sind  auf hohem Niveau:

Ernährungstabelle
Numerologie
Kalender
Verexexcelung von Paragrafen
Anwesenheitslistenplan
Quartalsproblemlösung

genug Lesestoff und Probierstoff für Wochen und nur ein Bruchteil dieser Seite insgesamt...



Impressum
Datenschutz