Phanom
Anmeldungsdatum: 28. April 2013
Beiträge: Zähle...
|
Hallo Gurus ich habe von einem bekannten 3 Festplatten bekommen diese sollen die gleichen Dateien haben.
Rsync kann nicht verwendet werden da unterschiedliche Ordnerstruktur. also
sda1 hat Ordner Datum/bild1.jpg sdb1 aber Kamera/irgendwas/bild1.jpg
sda1/Datum/bild2.jpg dies ist nicht auf der sdb1 und soll dorthin in einen neuen Ordner kopiert werden der Ordner sollte dann sync heißen. meine Idee ist
lese auf sda1 die Dateien aus und suche sie rekursiv auf sdb1
find -type f wenn nicht vorhanden dann -exec cp /sdb1/sync/ ich hab keine Ahnung wie ich das am dümmsten anstelle. hoffe Ihr versteht was ich meine und danke für eure Unterstützung. Gruß Phanom
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7657
|
Zum halbwegs effizienten finden doppelter Dateien unabhängig vom Dateinamen gibt es z.B. fdupes. Vergleiche paarweise a mit b, a mit c, b mit c: fdupes --recurse /mnt/a /mnt/b
fdupes --recurse /mnt/a /mnt/c
fdupes --recurse /mnt/b /mnt/c Die nicht-doppelten Dateien müssten dann jeweils kopiert werden. Wenn du das nicht von Hand machen willst, brauchst du ein Script, das die Ausgabe von fdupes auswertet. Wenn die Dateinamen stimmen und nur die Ordnerstruktur anders ist, könnte man da evtl. auch was anderes mit anstellen...
PS: Ein Sonderfall der mir gerade einfällt ist daß eine Datei innerhalb einer Festplatte bereits schon doppelt vorhanden sein könnte. Man muss also auch die doppelten Dateien prüfen, daß eine auf /mnt/a und eine andere auf /mnt/b liegt. Also man kommt nicht drum herum, das zu scripten.
|
dingsbums
Anmeldungsdatum: 13. November 2010
Beiträge: 3547
|
-2 Dateien mit gleichem Namen, gleichem Zeitstempel und gleicher Größe könnten theoretisch unterschiedliche Inhalte haben und daher nicht gleich sein. Wirkliche Duplikate findest du meines Wissens nur über einen Prüfsummenvergleich heraus, erstellt z.B. mit md5sum.
Wie das als Vergleich über nicht identische Verzeichnisbäume umgesetzt werden kann, ist mir momentan auch noch nicht klar.- Edit: Das von Frostschutz vorgeschlagene fdupes tut das wohl so.
Searches the given path for duplicate files. Such files are found by comparing file sizes and MD5 signatures, followed by a byte-by-byte comparison.
Wieder was gelernt ☺
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7657
|
OK, der Teufel steckt wie immer im Detail... fdupes gibt ja die einzelnen Dateien gar nicht aus, die man kopieren müsste. Der fdupes-Fork jdupes (in Ubuntu Universe) hat dazu eine --printunique Option... aber so richtig passt das auch nicht zu deinem Anwendungsfall. Das Script wird dann doch komplizierter als zuerst gedacht. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 | #!/bin/bash
#
# Compare two directories
#
set -euo pipefail
IFS=$'\n\t'
if [ $# -ne 2 -o ! -d "$1" -o ! -d "$2" ]
then
echo "Usage: $0 <sourcedir> <targetdir>"
exit 1
fi
sourcedir="${1%/}/"
targetdir="${2%/}/"
sourcefiles=$(find "$sourcedir" -type f)
targetfiles=$(find "$targetdir" -type f)
sourcetargetfiles=$(
set --
source=0
target=0
fdupes --recurse "$sourcedir" "$targetdir" |
while read line
do
if [ -z "$line" ]
then
if [ $source -eq 1 -a $target -eq 1 ]
then
printf "%s\n" "$@"
fi
set --
source=0
target=0
else
set -- "$line" "$@"
[ $source -eq 0 ] && [ "${1:0:${#sourcedir}}" == "$sourcedir" ] && source=1
[ $target -eq 0 ] && [ "${1:0:${#targetdir}}" == "$targetdir" ] && target=1
fi
done
)
sourceuniquefiles=$(printf "%s\n" "$sourcefiles" "$sourcetargetfiles" "$sourcetargetfiles" | sort | uniq -u)
targetuniquefiles=$(printf "%s\n" "$targetfiles" "$sourcetargetfiles" "$sourcetargetfiles" | sort | uniq -u)
printf "%s\n" "$sourceuniquefiles"
echo ""
printf "%s\n" "$targetuniquefiles"
# TODO: copy sourceuniquefiles to targetdir/sync
# TODO: copy targetuniquefiles to sourcedir/sync
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12823
|
Phanom schrieb:
meine Idee ist
lese auf sda1 die Dateien aus und suche sie rekursiv auf sdb1
find -type f wenn nicht vorhanden dann -exec cp /sdb1/sync/
Das ist natürlich furchtbar ineffizient, weil für jede gefundene Datei ein find über die anderen Datenträger gestartet werden muss.
hoffe Ihr versteht was ich meine und danke für eure Unterstützung.
Größtenteils. Was mir allerdings nicht 100% klar ist: was soll das Kriterium für Dateigleichheit sein? Ist es wirklich nur der Dateiname? Das wäre ja relativ unzuverlässig, wenn Dateinamen sich wiederholen können. Wenn man über den Inhalt gehen will, könnte man z.B. md5sum nutzen. Vorgehen wäre dann grob: Auf jedem Baum führt man aus find /start-1 -type f -exec md5sum {} + > start-1.sums Dann sort start-1.sums start-2.sums start-3.sums | cut -c 1-32 | uniq -c | awk '$1 != 3 {print $2}' >move-candidate-sums Schleife über alle sums und dann sucht man in start-* um herauszufinden, von wo nach wohin kopiert werden muss.
|
Phanom
(Themenstarter)
Anmeldungsdatum: 28. April 2013
Beiträge: 222
|
Hallo Danke für die Antworten frostschutz Respekt für das Script verstehe aber nur Bahnhof ☺ mein Ansatz war eigentlich 2 Dateien vergleichen und die es nicht gibt einfach zu kopieren doppelte Dateinamen sollten mit ein Zähler hinten dran erweitert werden
| #!/bin/bash
cd sda1
find -type f >> /tmp/sda-test1
sed 's#^.*/##' /tmp/sda-test1 >> /tmp/sda-test2
cd sdb1
find -type f >> /tmp/sdb-test1
sed 's#^.*/##' /tmp/sdb-test1 >> /tmp/sdb-test2
cd /tmp
grep -vxf sda-test2 sdb-test2
|
dann wäre auch nicht mehr so viele übrig und man könnte es kopieren mit ein einlesen der Datei als variable
finde die variable auf sda1 und kopiere dies nach sdb1/sync sollte datei vorhanden sein erweitere die Endung mit -1 -2 -3 usw PS:
ich habe leider kein Ubuntu mehr muss erst mal fdupes compilieren (gentoo) aber hier ist immer noch das beste Forum was ich kenne deswegen frage ich hier ☺
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12823
|
rklm schrieb:
Wenn man über den Inhalt gehen will, könnte man z.B. md5sum nutzen. Vorgehen wäre dann grob: Auf jedem Baum führt man aus find /start-1 -type f -exec md5sum {} + > start-1.sums Dann sort start-1.sums start-2.sums start-3.sums | cut -c 1-32 | uniq -c | awk '$1 != 3 {print $2}' >move-candidate-sums Schleife über alle sums und dann sucht man in start-* um herauszufinden, von wo nach wohin kopiert werden muss.
Mir fällt gerade auf, dass der Ansatz die Schwäche hat, mit doppelten Dateien auf einem Datenträger nicht gut umzugehen. Ich glaube, ich würde ab Schritt 2 ein Ruby-Script verwenden. Grobe Idee: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 | #!/usr/bin/ruby
require 'set'
def update_root(r, f)
return f unless r
[r.length, f.length].min.downto(1) do |i|
a = r[0...i]
b = f[0...i]
return a if a == b
end
nil
end
all_hashes = Set.new
roots = []
file_index = ARGV.map do |file|
Hash.new {|h,k| h[k]=[]}.tap do |hsh|
root = nil
File.foreach file do |line|
if /^(\h{32}\s\s(.*)$/ =~ line
key = Integer($1, 16)
all_hashes << key
hsh[key] << $2
root = update_root(root, $2)
else
abort "ERROR: Cannot read in #{file} line: #{line}"
end
end
roots << root
end
end
all_hashes.each do |key|
found = file_index.map {|idx| idx[key].first}
source = found.find {|x| x}
found.each_with_index do |f,i|
if f.nil?
puts "copy #{source} to #{roots[i]}/sync"
end
end
end
|
Edit: #downto(1)
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7657
|
find hat auch printf, da brauchst nicht mit sed nachbearbeiten # gibt nur dateinamen aus
find -type f -printf "%f\n" Dateinamen die es nur auf der a/-Seite gibt: (
find a/ -type f -printf "%f\n" | sort -u
find b/ -type f -printf "%f\n%f\n"
) | sort | uniq -u find a/ | sort -u gibt nur eindeutige Namen auf a-Seite aus (Sonderfall für doppelte Dateinamen innerhalb a)
find b/ -printf "%f\n%f\n gibt jeden Dateinamen auf b-Seite doppelt aus die damit alle rausgefiltert werden
uniq -u gibt nur eindeutige Namen aus, es bleiben also nur Namen auf a-Seite übrig die auf b-Seite nicht existieren
Ist halt die Frage ob du wirklich nur nach dem Dateinamen gehen willst. Musst du wissen.
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7657
|
Das gleiche mit rklm's md5sum (ohne fdupes): # prüfsummen für a/ und b/
find a/ -type f -exec md5sum {} + > a.sums
find b/ -type f -exec md5sum {} + > b.sums
# doppelte herausfiltern
cut -c 1-32 < a.sums | sort -u > a.usums
cut -c 1-32 < b.sums | sort -u > b.usums
# prüfsummen die a/ hat aber b/ nicht
cat a.usums b.usums b.usums | sort | uniq -u
# prüfsummen die b/ hat aber a/ nicht
cat b.usums a.usums a.usums | sort | uniq -u Das geht dann nur schief wenns zwei verschiedene Dateien mit der gleichen md5sum gibt. 😉 Und es werden dafür alle Dateien auf allen Platten eingelesen, selbst wenn diese gar nicht doppelt sein können (gleiche Dateigröße). Das ist das was fdupes eigentlich effizienter macht, aber da in diesem Fall es ja gerade so gedacht ist, daß alle Dateien doppelt vorkommen sollen, kommt man ja ohnehin nicht herum, alle Dateien einzulesen. Sogesehen ist der Ansatz einfacher.
|
dingsbums
Anmeldungsdatum: 13. November 2010
Beiträge: 3547
|
Hier mein Vorschlag. Ähnlich der Variante von Frostschutz, aber unabhängig entstanden. Die Variablen oben müssen angepaßt werden und der eigentliche Kopierbefehl (Zeilen 21 + 36) in den Ordner der Wahl muss man auch noch ergänzen. Dateien mit Größe 0 Bytes werden ignoriert, die haben immer die gleiche md5-Summe. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | #!/bin/bash
ordner1="aaa"
ordner2="bbb"
liste1="dateiliste_aaa.txt"
liste2="dateiliste_bbb.txt"
find $ordner1 -type f -exec md5sum {} + > $liste1
find $ordner2 -type f -exec md5sum {} + > $liste2
echo vergleiche ordner $ordner1 mit $ordner2, ignoriere dateigröße 0 ...
cat $liste1 | while read zeile;do
md5sum="$(echo $zeile | awk '{print $1}')"
rest=${zeile##$md5sum}
dateipfad="$(echo $rest | sed -e 's/^[ \t]*//')"
if [ ! "$(stat -c %s "$dateipfad")" == "0" ];then
grep $md5sum $liste2 &>/dev/null
if [ ! $? -eq 0 ];then
echo $dateipfad ist nicht in $liste2 und muss nach $ordner2 kopiert werden
# hier dein kopierbefehl
fi
fi
done
echo
echo vergleiche ordner $ordner2 mit $ordner1, ignoriere dateigröße 0 ...
cat $liste2 | while read zeile;do
md5sum="$(echo $zeile | awk '{print $1}')"
rest=${zeile##$md5sum}
dateipfad="$(echo $rest | sed -e 's/^[ \t]*//')"
if [ ! "$(stat -c %s "$dateipfad")" == "0" ];then
grep $md5sum $liste1 &>/dev/null
if [ ! $? -eq 0 ];then
echo $dateipfad ist nicht in $liste1 und muss nach $ordner1 kopiert werden
# hier dein kopierbefehl
fi
fi
done
|
|
Phanom
(Themenstarter)
Anmeldungsdatum: 28. April 2013
Beiträge: 222
|
Ihr seit die BESTEN vielen dank werde es doch über Prüfsumme machen danke für eure Hilfe komme immer wieder gern hier her. Sorry an alle anderen aber die entscheidung feld auf dingsbums da verstehe ich alles und an frostschutz danke für das erklären von | find -type f -printf "%f\n"
|
wieder was dazugelernt und für euer bemühen moch ein ganz GROSSES DANKESCHÖN und nicht böse sein das ich nicht gleich das erste genommen habe. Gruß Phanom
|
dingsbums
Anmeldungsdatum: 13. November 2010
Beiträge: 3547
|
Noch ein Tipp zum Kopieren: Damit nicht alle zu kopierenden Dateien unstrukturiert im Zielordner landen und Dateien bei Namensgleichheiten überschrieben werden, verwende zum Kopieren ein cp --parents . Dann wird die Ordnerstruktuktur aus dem Quellordner für die Datei im Zielordner angelegt. Beispiel:
cp --parents --verbose /boot/grub/grub.cfg aaa/
/boot -> aaa/boot
/boot/grub -> aaa/boot/grub
'/boot/grub/grub.cfg' -> 'aaa/boot/grub/grub.cfg'
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Du hättest mal beantworten können, ob die Namen eindeutig sind. Genug Platz auf sdb1 vorausgesetzt, könntest Du stumpf alle Dateien von sda1 nach sdb1 kopieren und dann die doppelten mit fdupes löschen, allerdings habe ich kein fdupes und weiß nicht, wie man es optimal einsetzt.
|