Find duplicates

A probléma Szorgosan fotózunk. Idővel rákapunk arra is, hogy a fényképeinket szépen rendszerezett formában tároljuk valamelyik fotós workflow alkalmazás segítségével. A fotóink egy folder struktúrába importálódnak, példás rendben. Minden oké, amikor egyszer csak véletlenül egy nagy kupac régi képet kétszer húzunk be a libraryba – kész a baj, egy zsák fotónk lesz meg két példányban, feleslegesen. Lista kellene a duplikált file-jainkról!

A megoldás

Mielőtt alkalmazást keresnénk a feladat leküzdésére, agyalunk egy kicsit és kitaláljuk, hogy *nix-like környezetben menni fog ez külső segítség nélkül is. Két file egyezésének megállapításához pont elég, ha azok MD5 hash-e megegyezik. Írjunk hát egy scriptet, amely az egyező MD5 hash-ek alapján elkészít egy duplikált file listát:
# A script a duplikált file-okat tartalmazó foldert várja paraméterként
# és a jpg kiterjesztésű állományok egyezését vizsgálja csak.
NAME="*.jpg"
ALLFILES="/tmp/finddups.allfiles.tmp"
DUPHASHES="/tmp/finddups.duphashes.tmp"
find $1 -name "$NAME" -exec md5 {} \; | sort >$ALLFILES
find $1 -name "$NAME" -exec md5 -q {} \; |sort|uniq -d|sort -n >$DUPHASHES
while read hash
do
	cat $ALLFILES | grep $hash | grep -oE '\((.*-[0-9].jpg)\)' | sed "s/(// ; s/)//"
done <$DUPHASHES
Nézzük meg, mit csinálunk. Az első find-del kezdődő sor a célfolderben levő összes jpg file-unkból számol egy MD5 hash-t, majd a filelistát hash-estől leteszi egy file-ba. Ez a file valahogy így fog kinézni:
MD5 (./2000/05/15/20000515-0084.jpg) = 747888000b422d619a1b308346b7d81e
MD5 (./2000/05/15/20000515-0086-2.jpg) = d3a064924fb8306519475b09cb90d66b
MD5 (./2000/05/15/20000515-0086-3.jpg) = d3a064924fb8306519475b09cb90d66b
MD5 (./2000/05/15/20000515-0086.jpg) = d3a064924fb8306519475b09cb90d66b
A következő sorban mégegyszer végigmegyünk a jpg filejainkon, de csak az MD5 hash-üket kérjük, mindenféle sallang nélkül (=ezt adja az md5 -q opciója), majd a uniq binárissal csak a duplikált hash-eket szűrve (=-d opció) letesszük az összes, többször előforduló MD5 hasht egy másik file-ba. Ezután már csak végig kell rohannunk a duplikált hash-eken, kikeresni, hogy mely file-okhoz tartoznak és kilistázni azokat – ezt teszi a script végi ciklus. A ciklus közepén levő regexp arra hivatott, hogy az első körben előállított hash-es filelistából csak a filenevek jelenjenek meg – azok közül is csak azok a file-ok, amelyek neve -[0-9].jpg-re végződik. Tudom, hogy a végén levő sed (amellyel a kibányászott filenevek elől és mögül lecsippentjük a zárójeleket) ágyúval verébre kategória. Nekem sem tetszik, gusztustalan – azonban szűk egy órán át nem találtam más megoldást, ezért maradt ilyen. Commentben lehet szárnyalni, ki hogyan választaná le így shellben az egrep által elkapott első capture group-ot.]]>

7 thoughts on “Find duplicates

  1. eFi Post author

    Egy sed valóban szebb, de én egy szép grepet akarok 🙂 Azért beírtam egy pirosat!

    Reply
  2. eti

    grep -oE ‘[^(]*-[0-9].jpg’
    # feltéve, hogy a fájlnévben nincs ‘(‘
    vagy
    grep -oE ‘\./.*-[0-9].jpg’
    # ha a find által odarakott ‘./’-t biztos meghagyod később is

    Reply
  3. orrmany

    Az én tippem: karaktertörlésre használj célszerszámot (KISS szabály):
    tr -d ‘()’
    KISS szabályból, illetve munkahelyi ártalomból fakadó további tipp: ne menj végig 2. a fájlokon a $DUPHASHES előállításához (rengeteg LASSÚ disk I/O kell hozzá), ha eleve ott van már minden infó, ami kell neked az ALLFILES-ben:
    cat $ALLFILES | cut -d “=” -f 2 | sort -n | uniq -d | tr -d ‘ ‘ >$DUPHASHES

    Reply
  4. orrmany

    Ha ragaszkodsz a regexphez, akkor íme egy egyszerű megoldás, ami elfogad zárójelet a fájlnév közepében, de leszedi az első nyitót és utolsó csukót:
    egrep -o ‘[^(].*[^)]’

    Reply

Leave a Reply

Your email address will not be published.