Forum: PC-Programmierung Linux Kommandozeile, Dateien kopieren


von Robert (Gast)


Lesenswert?

Moin,

folgende Problematik:

Ich habe eine Menge sehr schlampig archivierte Dateien mit einer 
bestimmten Endung quer verteilt auf einem riesigen Dateisystem. 
Erschwerend kommt hinzu, dass einige dieser Dateien in verschiedenen 
Verzeichnissen zwar den gleichen Namen haben (super Beispiel: 
"aktuell.bla" oder "test.bla"), aber einen unterschiedlichen Inhalt. Es 
gibt auf der anderen Seite auch jede Menge identische Dateien, die in 
verschiedenen Verzeichnissen abgelegt sind.

Ich möchte alle diese Dateien nun gerne in EIN Verzeichnis kopieren, und 
zwar so, dass Dateien, die aus unterschiedlichen Verzeichnissen kommen, 
aber den gleichen Namen haben, sich nicht gegenseitig überschreiben. 
D.h., sie müssen einen anderen Namen bekommen oder ich muss die 
Verzeichnisstruktur mitkopieren (aber eben nicht andere Dateien, die 
sonst in diesem Verzeichnisbaum liegen.)

Der resultierende Dateiname wäre erstmal fast egal, da ich den 
Originaldateiname aus dem Inhalt wiederherstellen kann. Dafür habe ich 
mir schon ein Script gebaut.

Mein Ziel ist es, alle diese Dateien (ohne Duplikate und ohne Verlieren 
von verschiedenen Dateien mit gleichem Namen) in einem Verzeichnis zu 
haben.

Bisher war mein Ansatz folgender:

1. Alle Dateien der Endung "bla" mit "find -iname *.bla >liste.txt" 
ausfindig machen und die Liste aller Dateien inkl. komplettem Pfad in 
eine Textdatei schreiben

2. Über ein Bash-Script die Datei einlesen und für jede einzelne Datei 
"cp" aufrufen, um diese in ein gemeines Verzeichnis zu kopieren. Hier 
entsteht natürlich die Überschreibe-Problematik. Wie löse ich das?

3. Mit "fdupes" die Duplikate löschen

3. Mit Hilfe meines Scriptes den Originaldateinamen wiederherstellen.

Fertig.

Wer kennt sich aus und kann mir bei Punkt 2 helfen? Schön wäre zum 
Beispiel eine Alternative zu "cp", die es schafft, den Pfad 
mitzukopieren. "cp" kann das zwar, aber nur mit der Option "-r", die 
dann alle anderen Dateien und Unterverzeichnisse mitkopiert.

von Sebastian (Gast)


Lesenswert?

Kleine Ideensammlung:

Ich würde die Punkte (2) und (3) kombinieren. Wenn du in (1) schon die 
Liste der Dateinamen hast ("liste.txt"), kannst du mit

  $ cat liste.txt | xargs -d '\n' md5sum | sort -k 1 > md5sum.txt

eine sortierte Liste von MD5-Prüfsummen mit dazugehörigen Dateinamen 
bekommen. Diese Liste müsstest du derart aufbereiten, dass mehrfach 
aufeinanderfolgende Zeilen mit gleicher Prüfsummenspalte ignoriert 
werden.

Angenommen, die bereinigte Datei ist in "md5sum-uniq.txt", dann kannst 
du wieder mit einem kleinen Skript jede Zeile dieser Datei durchwandern 
und die angegebene Datei in dein Zielverzeichnis kopieren. Dabei würdest 
du die entsprechende Prüfsumme als Dateinamen verwenden.

Ergebnis: Keine Kollisionen bei gleichem Dateinamen aber verschiedenem 
Inhalt, und jeder Dateiinhalt taucht nur einmal als Datei im 
Zielverzeichnis auf.

Als letzten Schritt stellst du mit deinem existierenden Skript die 
Dateinamen aus dem Inhalt wieder her.

Dabei wird natürlich angenommen, dass MD5 ein brauchbarer Hash für 
Dateiinhalte ist. Um die Wahrscheinlichkeit, dass zwei unterschiedliche 
Dateien als gleich erkannt werden (gleiche Prüfsumme) zu verringern, 
kannst du zusätzlich zu "md5sum" mit (bspw.) "sha1sum" eine zweite Liste 
erstellen, wahlweise auch mit anderen Hash-Verfahren.

Im Zweifel kannst du ja beim Bereinigen der Liste darauf achten, welche 
Dateien übersprungen würden und diese manuell auf wirklich 
unterschiedlichen Inhalt prüfen.

Sebastian.

PS: Noch ein Tipp: Statt die Dateien zu kopieren (wenn du die Originale 
danach eh löschst), kannst du auch hard-links erzeugen (z.B. mit "cp -l" 
oder "ln"). Vorteil: Es geht deutlich schneller, da der Dateiinhalt 
nicht dupliziert werden muss, außerdem bestehen die Originale danach 
noch fort. Nachteil: Änderungen an den "Kopien" wirken sich auf die 
Originale aus und umgekehrt.

von mar IO (Gast)


Lesenswert?

Robert schrieb:
> 2. Über ein Bash-Script die Datei einlesen und für jede einzelne Datei
> "cp" aufrufen, um diese in ein gemeines Verzeichnis zu kopieren. Hier
> entsteht natürlich die Überschreibe-Problematik. Wie löse ich das?

Entweder Du schaust zuvor nach, ob schon eine Datei vorhanden ist ("test 
-e ...") oder Du lässt cp die vorhandene Datei nicht überschreiben ("cp 
-n ..."). "$?" wird entsprechend gesetzt oder man macht es irgendwie so: 
"test -n dat1 dat2 || echo Fehlschlag".

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.