File-Duplikate in einem Verzeichnis löschen und symbolisch verlinken.

@TCM: Das nuetzt noch immer nichts, wenn \n im Dateinamen ist.

Hier mal ein kurzes Perl-Stueck, welches im Prinzip fast fertig ist, man muss nur noch die Funktion schreiben, welche einem den relativen Pfad zur Link-Quelle zurueckgibt.

Code:
#!/usr/bin/perl -w

use File::Find;
my %md5;

$ARGV[0] = '.' if (!@ARGV);
finddepth({wanted => \&action, no_chdir => 1}, @ARGV);

sub action {
  return unless -f;
  return if -l;
  chomp ($hash = `/sbin/md5 -q $_`); #FIXME errorcheck
  if (defined($md5{$hash})) {
    $path = &relpath($md5{$hash}, $_);
    exec("/bin/echo","/bin/ln","-sf","$path","$_") == 0 or
      die "Can't link $_ to $md5{$hash}: $?";
  } else {
    $md5{$hash} = $_;
  }
}

# TODO Return shortest possible relative path from second
# to first argument
sub relpath {
  return $_[0];
}
 
MrFixit schrieb:
@TCM: Das nuetzt noch immer nichts, wenn \n im Dateinamen ist.
hmm, ich koennte jetzt sagen, dass ich nirgendwo ein \n in dateinamen habe, je gesehen haette oder fuer unterstuetzenswert halte. stattdessen sag ich mal: stimmt.
 
MrFixit schrieb:
@TCM: Das nuetzt noch immer nichts, wenn \n im Dateinamen ist.

Hier mal ein kurzes Perl-Stueck, welches im Prinzip fast fertig ist, man muss nur noch die Funktion schreiben, welche einem den relativen Pfad zur Link-Quelle zurueckgibt.

das problem habe ich auch schon bemerkt und angepackt.

dazu nehme ich zu jedem filename den voll qualifizierete path
und lösche den filename. habe vergessen das script von der arbeit
nachhause zu mailen, deshalb kann ich erst morgen weiermachen
aber ungefehr siehts so aus bei mir (kenne ja kein perl):

duplicates.files = liste alle duplicate mit nur filename
duplicates.toc = liste aller files mit fully qual. path + filename


for i in$(cat dusplicates.files)
do grep $i duplicates.toc | sed -e 's/'$i'//' >> duplicates.dirs
done

also aus
./ml5302/dir/dir2/filename
wird
./ml5302/dir/dir2/

wie man das in perl schreibt musst du selbser wissen,
ich bin sowieso morgen damit fertig.

also beeil dich mal ;) :D

EDIT: ich habe sogar alle md5 dateien,
fehlt für morgen nur vergleichen und löschen+linken falls gleich.

ach ja, und aufräumen und kürzer machen,
ich mag es mit viel zeilen damits leichter nachvollziehbar ist,
aber insgesammt kann man sehr viele zeilen sparen.
ist dann halt nicht mehr zu lesen für nuubs.

mal abgesehen von der tatsache dass es von nem nuub geschrieben wurde.... :D
 
tobiasbeil schrieb:
duplicates.files = liste alle duplicate mit nur filename
duplicates.toc = liste aller files mit fully qual. path + filename


for i in$(cat dusplicates.files)
do grep $i duplicates.toc | sed -e 's/'$i'//' >> duplicates.dirs
done

also aus
./ml5302/dir/dir2/filename
wird
./ml5302/dir/dir2/
man dirname oder auch: $file enthaelt kompletten pfad+dateiname, dann ist ${file%/*} nur der pfad.
 
tobiasbeil schrieb:
dazu nehme ich zu jedem filename den voll qualifizierete path
und lösche den filename. habe vergessen das script von der arbeit
nachhause zu mailen, deshalb kann ich erst morgen weiermachen
aber ungefehr siehts so aus bei mir (kenne ja kein perl):
...
for i in$(cat dusplicates.files)
do grep $i duplicates.toc | sed -e 's/'$i'//' >> duplicates.dirs
done

also aus
./ml5302/dir/dir2/filename
wird
./ml5302/dir/dir2/
Das ist nur leider nicht voll qualifiziert, du muesstest noch den pwd vorne ranhaengen. Wenn du jetzt verlinkst, dann kommt da immernoch bullshit raus.

Desweiteren solltest du dir dirname ansehen, wie bereits erwaehnt wurde.

Zu Perl: Lerne lieber ein paar Zeilen Perl, als sh-Skripten. Im Endeffekt ist Perl schneller/maechtiger/komfortabler/etc.

PS: deine sed(1) Zeile geht vollkommen Hopps, wenn Sonderzeichen vorhanden sind. Warum nimmst du nicht sed -e "s/$i//" ? Du hast noch viel zu lernen, junger Jed^H^H^HUnix-Ritter.
 
MrFixit schrieb:
PS: deine sed(1) Zeile geht vollkommen Hopps, wenn Sonderzeichen vorhanden sind. Warum nimmst du nicht sed -e "s/$i//" ? Du hast noch viel zu lernen, junger Jed^H^H^HUnix-Ritter.

sed -e 's/'${i}'//' hat funktioniert und nichts anderes,
habe es mir nicht aus der nase gezogen sondern extra getestet.
(zumindest gehts nur so auf der AIX und nicht anders)

Join the Dark Side.

"UUUUNLIIMITED POW-AAAAAA !!!"
 
ist doch egal, das hat an irgendeiner stelle gehackt,
deswegen hab ichs überall "korrekt" übernommen,
und schaden tuts ja auch nicht.... ;)


EDIT:

Wichtige Frage:
Um das script total "sauber" zu kriegen bräucht ichan einer
bestimmten stelle wissen, ob man verzeichnisse mit unterverzeichnissen
"direkt" erstellen kan, ohne zu erst manuell die vaterverzeichnisse erstellen
zu müssen.
also, angenommen ./vater existiert nicht und ich will ./vater/sohn/ erstellen...
# mkdir ./vater/sohn/
schläg fehl, weil sohn nicht erstellt werden kann, weil vater fehlt.
gibts nen befehl oder trick, wie man a la "create directory if it doesnt exist"
verzeichnisse ersellten kann mit sh/bash tricks ?

Wäre echt super, weil dann könnte ich die md5 dateien im /tmp ordner
speichern, statt im eigentlichen verzeichniss, wo die Duplikat-Dateien sind.

EDIT2:
problem gelösst:
#mkdir -p ./vater/sohn/
 
Zuletzt bearbeitet:
wie lautet die äquivalente schreibweise zu diesem pseudo code:

# for i in $(echo 123) and j in $(echo 456)
do echo $i$j
done

123456
# _

ich will nur 2 variablen in einer for schleife definieren dürfen.


EDIT:
hier ein konkreteres beispiel was ich machen will:

# for i in $(echo 123;echo abc) and j in $(echo 456;echo def)
do echo $i$j
done

123456
abcdef
# _
 
Update:

Code:
siehe Beta unten

UPDATE2:
Hier ein viel besserer weil schnellerer Ansatz:

Code:
siehe Beta unten
 
Zuletzt bearbeitet:
So,

ich bin jetzt fast fertig, fehlt nur noch eine gescheite Ausnahmebehandlung,
falls filename und size identisch, aber MD5 verschieden ist. Ist nicht so trivial...

Hier der aktuelle code so far:

Code:
siehe Beta unten

Da wo "echo Same filename and ...." steht kommt später der code für den entsprechnden fall rein.
Ich arbeite zwar nur nebenbei daran, aber heute ist freitag, kann sein dass ich komplett fertig werde.

stay tuned.
 
Zuletzt bearbeitet:
tobiasbeil schrieb:
Code:
for filenames in $(cat ${wd}/uniq.filenames)
	do for sizes in $(cat ${wd}/uniq.sizes)
		do if [ -d ${wd}/duplicates/${filenames}.${sizes} ]
		   then
		   	${opt}find . -type f -name ${filenames} -size ${sizes}c -printf '%p\n' > ${wd}/duplicates/${filenames}.${sizes}/duplicates.paths
		   	for paths in $(cat ${wd}/duplicates/${filenames}.${sizes}/duplicates.paths)
				do md5sum=$(md5sum ${paths} | head -c 32)
				   echo ${paths} >> ${wd}/duplicates/${filenames}.${sizes}/${filenames}.${sizes}.${md5sum}.md5
				done
			#endfor
			uniq -d ${wd}/duplicates/${filenames}.${sizes}/duplicates.md5tmp > ${wd}/duplicates/${filenames}.${sizes}/duplicates.md5
			rm -f ${wd}/duplicates/${filenames}.${sizes}/duplicates.md5tmp
			if [ ! -s ${wd}/duplicates/${filenames}.${sizes}/duplicates.md5 ]
		   	then
				head -n 1 ${wd}/duplicates/${filenames}.${sizes}/duplicates.paths > ${wd}/duplicates/${filenames}.${sizes}/duplicates.src
				cat ${wd}/duplicates/${filenames}.${sizes}/duplicates.src ${wd}/duplicates/${filenames}.${sizes}/duplicates.paths | uniq -u > ${wd}/duplicates/${filenames}.${sizes}/duplicates.links
				srctmp=$(cat ${wd}/duplicates/${filenames}.${sizes}/duplicates.src)
				for links in $(cat ${wd}/duplicates/${filenames}.${sizes}/duplicates.links)
					do rm -f ${links}
					   ln -s ${srctmp} ${links}
					done
				#endfor
				srctmp=
			else
				echo Same filename and size, but different MD5 sum.
			fi
		   fi
		done
	done
#endfor

# Cleaning up
rm -fr ${wd}

exit 0
also ich will ja nicht schon wieder maekeln, aber alleine der block da oben wirft die frage auf: bist du sicher, dass du da selber in einem monat noch durchblickst, geschweige denn jemand anders?
 
Ich bin jetzt endgültig fertig und teste nur noch rum (dauert halt ewig bei grossen dateien).

@tcm

friss oder strirb, take it or leave it.
ich kenne nix für AIX was dasselbe macht und fdupes läuft auch nicht auf AIX,
ich musste das script eigentlich schon schreiben und jeder, der nen NIM Master server für mehrere OSs betreibt wird mir dankbar sein.

Hier der vorläufige Code zum testen,
das "programm" ist fertig und es "fehlt" nichts mehr,
d.h. dies ist die erste echte Beta wenn ihr so wollt:

Code:
siehe ersten Beitrag für neueste Version.

EDIT:

zur "Erklärung" wollt ich noch sagen, dass ich das script nun auf schnelligkeit optimiert habe im sinne der klassischen komplexitätsdefinition,
zu deutsch: ich wollte so wenig dateien wie nur möglich, also nur wenns nötig ist,
auf md5 summe überprüfen, weil besonders bei grossen dateien dies den flaschenhals in der laufzeit dieses scripts ausmacht, weniger die "script-logik" selbst.

ausserdem hatte ich probleme ergebnisse wie allerlei auswerungen auf dateinamen, dateigrössen und md5 summen den jeweiligen dateien zuzuordnen,
deshalb habe ich diese Zwischen-"Ergebnisse" etwas unorthodox "gespeichert", teilweise indem ich normale Ordner erstellen lasse, die von der Nomenklatur bzw wie sich der Name aufbaut so beschaffen sind, dass man auf viele "echte Dateien", welche Ergebnisse speichern verzichten kann, leider werden entsprechend viele ordner erstellt und auch dateien.

EDIT2:

auf Linux müsst ihr "opt=" auf nichts setzten statt auf /opt/freeware/bin,
einfach aus- und einkommentieren, wie es beschrieben ist.
 
Zuletzt bearbeitet:
@myself

öhm ?
rmdupl.sh[18]: 0403-057 Syntax error at line 60 : `'' is not matched.

???

Ist mir garnicht aufgefallen, weil ich teilweise die befehle einzeln eingegeben habe
um nicht ewig warten zu müssen bis alles "auf einen schlag" funktioniert...

Wo ist denn der hacken ?
Wenn ich die befehle einzelne per copy and paste dem putty übergebe (rechte maustaste=paste)
dann schluckt er das, aber jetzt per "sh rmdupl.sh" kommt die fehlermeldung ? :apaul:

Hilfe bitte!


EDIT:

mann, bin ich mal dumm und dämlich.... ich habe ja die ganzen Echos nicht mitgetestet,
weil ich dachte des ist unwichtig, dabei war gleich das erste echo ganz falsch formuliert,
denn das use's " ' " welches "use" und "s" trennt ist so wie ich es schrieb unerlaubt,
einfach zeile mit echo auskommentieren, aber ich habe den code oben nun "gefixt".
 
Zuletzt bearbeitet:
hier mal ein quick(!) hack:
Code:
#!/bin/sh

tmphash=""
tmpfilename=""

find . -type f | while read filename
    do
        md5 -n "${filename}"
    done | sort | while read hash filename
    do
        if [ "${tmphash}" = "${hash}" ]; then
            rm -f "${filename}"
            ln "${tmpfilename}" "${filename}"
        else
            tmphash="${hash}"
            tmpfilename="${filename}"
        fi
    done
funktioniert rekursiv, mit space in dateinamen und linkt mit hardlinks statt symlinks. fuer symlinks muesste man das script anpassen, da es die linkziele nicht korrekt konstruiert. edit: es wird _nur_ der hash als gleichheitsmerkmal angenommen, man koennte die groesse noch dazunehmen oder beliebige andere merkmale.

edit: achja, benutzung auf eigene gefahr, hat zwar in nem kurzen test funktioniert, aber wer weiss.
 
Zuletzt bearbeitet:
@tcm

nice, aber ich habe ich 4000+ dateien, die sogar bis cd grösse 700+ gehen,
ich will einfach nicht JEDE datei hashen... es ist wirklich besser, wenn man
nur die "verdächtigen" dateien hashed, also filename gleich, size in bytes gleich
und nur unter diesen sollte man hashen, dann lohnt es sich wirlich und genau das
habe ich gerade realisiert, getestet, und entwurmt (enthielt tatsächlich noch ein paar fehler).

und das mit den hardlinks ist generell schwachsinn nebenbei. total gefährlich.
hard ist nicht gleich besser wie symbolish, falls du in solchen regionen denkst...

Hier der absolut FINALE und GETESTETE CODE:

rmdupl.sh:
Code:
siehe ersten Beitrag für neueste Version.

Die Speicherplatzersparnis ist immer unterschiedlich (bei mir sehr hoch),
aber das ist auch nicht zum aufs root verzeichnis anwenden, sondern wenn man
ja ganz genau vermutet, dass is einem verzeichnis duplicate sind.
Im root verzeichniss ausgeführt wüsste ich nicht was passieren würde mit den
/dev Gerätedateien, deswegen hab ich da ne schutzfunktion eingebaut, welche das
ausführen im root unterbindet.

Benutzung:

man wechselt zum verzeichniss wo man duplikate vermutet und startet "./rmdupl.sh".
um zu gucken wieviel speicherplatz man spart kann man zur info vorher "du" ausführen und sich
die letzte zeile merken. nach "rmdupl" dann dasselbe nochmal, und die letzte zeile sollte dann einen
kleineren wert haben.
mit "find . -type l" im verzeichnis wo man auch rmdupl ausgeführt hat kann man übrigends
sehen, welche dateien nun "nur" als symbolische Links da sind.

Have Fun.

PS: wer weitere nette verbesserungen zu bieten hat nur zu... ich erhebe keine Patente ;) ;) ;)
:cool:

EDIT:

code benutzt jetzt HARDLINKS... (aber sonst ist alles gleich...)
 
Zuletzt bearbeitet:
tobiasbeil schrieb:
und das mit den hardlinks ist generell schwachsinn nebenbei. total gefährlich.
hard ist nicht gleich besser wie symbolish, falls du in solchen regionen denkst...
da bin ich jetzt aber neugierig. kannst du das mal naeher ausfuehren?
 
ok, ganz konkret an meinem beispiel ok ?

also.

wir haben ein directory namens /export/nim

da drin befinden sich die installationsdateien für die ganzen verschiedenen AIX versionen zBsp:
/export/nim/Aix51/ml5105
/export/nim/Aix51/ml5106
/export/nim/Aix51/ml5107
/export/nim/Aix51/ml5108
/export/nim/Aix52/ml5200
/export/nim/Aix52/ml5201
/export/nim/Aix52/ml5202
/export/nim/Aix52/ml5203
/export/nim/Aix52/ml5204
/export/nim/Aix52/ml5205
/export/nim/Aix52/ml5206
/export/nim/Aix53/ml5300
/export/nim/Aix53/ml5301
/export/nim/Aix53/ml5302

/export/nim/spots/
/export/nim/spots/AIX51
/export/nim/spots/AIX52
/export/nim/spots/AIX53

...

und bald folgen auch die Install dateiten für RH 4 und SLES 9,

nun jedes verzeichniss MUSS die isntallationsdateien bereitstellen,
aber viele installationen dateien sind gleich, zum beispiel JAVA verändert sich
nicht mit jeder neuen AIX Version, da gibts bei uns nur Java131 und Java14
aber das dann in 14 Ordnern.
Jetzt zähle noch die nicht veränderten Devices und X und libs und sonstwas dazu,
das ist denn alles 14x vorhanden, mindestens.

wenn ich aber überall HARDLINKS mache und wir uns mal entscheiden
wir wollen eine bestimmte AIX version nicht mehr anbieten zum über netzwerk
installieren, und wir löschen nur einen der 14 ordner,
dann sind alle installationen am arsch, weil wenn du einen hardlink löscht,
sind alle dateien die darauf zeigen im arsch.

symb links kannst du löschen, das ist total egal,
nur die quelldateien darfste nicht löschen, sonst sind gleichzeitig alle symb links = /dev/null ;)

Nur deswegen.

grund genug ??

PS: du nervst total, musst immer was gegen meine beiträge sagen, was ? pff :rolleyes:
 
tobiasbeil schrieb:
wenn ich aber überall HARDLINKS mache und wir uns mal entscheiden
wir wollen eine bestimmte AIX version nicht mehr anbieten zum über netzwerk
installieren, und wir löschen nur einen der 14 ordner,
dann sind alle installationen am arsch, weil wenn du einen hardlink löscht,
sind alle dateien die darauf zeigen im arsch.
grober unfug.

symb links kannst du löschen, das ist total egal
aha...

nur die quelldateien darfste nicht löschen
wie, doch nicht egal? edit: die originaldatei ist natuerlich kein link, insofern..

tatsache ist, dass es die hardlinks sind, bei denen es voellig egal ist, welchen du loescht, solange einer uebrigbleibt. edit: insofern basiert deine wahl der symlinks auf einer falschen annahme und du kannst jetzt doch hardlinks benutzen?
 
TCM schrieb:
insofern basiert deine wahl der symlinks auf einer falschen annahme und du kannst jetzt doch hardlinks benutzen?

DAS, ...

ist ein Argument....

ich füge mich gerne.

ich update den code oben... einfach das "-s" bei "ln -s ..." wegmachen.
 
was denkt ihr davon eine weitere sicherheitsfunktion einzubauen,
um den fall zu berücksichtigen, wenn man rmdupl.sh mehrmals auf
verschiedenen verzeichnissen ausführt ? noch habe ich nicht in diese
richtig gedacht. es gibt zwei möglichkeiten dies anzupacken:

1. man verbietet mehrere instanzen.
2. man lässt mehrere verschiedene instanzen in voneinander abgeschotteten "working dirs" arbeiten.

nummer eins ist sehr einfach zu implementieren in 15 sec.
nummer zwei ist auch einfach, aber um die compabilität zw. veschiedenen OSen zu waren,
müsste ich erst rumtesten den "gemeinsamen nenner" zu finden.

ihr könnt mir schon mal helfen:

wie ist die standardmethode in Un*x zufallszahlen zu generieren ??

Es dürfen auch gerne pseudo-zufallszahlen sein, für diesen einsatzgebiet
haben wir keine wissenschafftlichen ansprüche.

bye.
 
tobiasbeil schrieb:
was denkt ihr davon eine weitere sicherheitsfunktion einzubauen,
um den fall zu berücksichtigen, wenn man rmdupl.sh mehrmals auf
verschiedenen verzeichnissen ausführt ?
sollte eigtl nicht aufgabe des scripts sein, aber wenns sein muss... edit: der satz ist natuerlich kaese, weils nicht um zwei instanzen im selben dir geht, sondern um das temp-dir.

1. man verbietet mehrere instanzen.
nae..

2. man lässt mehrere verschiedene instanzen in voneinander abgeschotteten "working dirs" arbeiten.
das ist dann immer das problem, wenn man uebermaessig temp-zeug anlegt.

wie ist die standardmethode in Un*x zufallszahlen zu generieren ??
pfui! :) man mktemp
 
Hallo miteinander!

Mein erster Post in diesem Forum. Eigentlich bin ich ein passiver Leser des Forums, aber der Thread hat mich jetzt spontan dazu bewogen mich zu registrieren.

Vor knapp vier Wochen habe ich ein kleines C-Programm geschrieben, das Dateiduplikate ermittelt. Hintergrund: Wir haben hier einen Solaris-Server, auf denen sich via Samba eine Menge Win-Daus tummeln, die leider eine extrem ineffiziente Arbeitsweise haben. Sie posten sich via Mail ihre aktuellen Dokumente zu und speichern diese Biester n-fach in ihren Verzeichnissen.

Das Programm 'redundancy'
http://www.usf.uos.de/~steichma/private/redundancy/
kann mit einer Mindestgröße und einen Mindestalter der Dateien parameterissiert werden.
Genaueres stheht in der README.

Vielleicht besteht Interesse, mal mit dem Ding rumzuspielen. Hat schon auf größeren Datenmengen efolgreich seinen Dienst getan. Als Backend könnte ich ein Skript schreiben, das evt. via Links gegen die Duplikaten-Plage vorgeht.

Gruß, Sascha
 
TCM schrieb:

gut, dass du mich auf mktemp aufmerksam gemacht hast,
sonst würde ich jetzt das rad neu erfinden....

:D :D

EDIT:
Hajo!, ... s'gibt koi emkatämp für's OIX. Wos macha'ma denn'u ?

Ich würde jetzt trotzdem gerne wissen was die standardmethode zum zufallszahlen
generieren ist bei Un*x systemen ...

Ich könnte ja mit dd if=/dev/random arbeiten, nur erzeugt das etwas arg zufällige bytes,
also auch nicht druckbare zeichen. :zitter:

EDIT2:

echo $RANDOM ...
tuts zur not auch.


EDIT3:

und wie immer der code update:

Code:
siehe ersten Beitrag für neueste Version.
 
Zuletzt bearbeitet:
und hier nochmal ein wunderschönes beispiel:

vorher
# du
...
..
.
32293848 (512 bytes blocks, nicht bytes)
~15,4 Gb

# sh rmdupl.sh
...
..
.
Done.

nachher
# du
18296791 (~ 8.7 Gb)

6,7 Gb gespart, das sind dann 43% weniger speicherplatz als vorher. :D :D :D :D

(liegt aber nicht am script, sondern an unseren Daten, ich gebe zu in unser fall ist ein extrembeispiel, aber immerhin... wenigstens ist mein script in weniger als 2 min. über die kompletten 15.4 gig gerasst.
Nicht auszudenken wenn man jede einzelne datei blind hashen würde... :rolleyes: )

:)
 
Zurück
Oben