angle-left

Дедупликация медиа своими руками

Долго рассуждая о дедупликации, настал момент когда мне потребовалось использовать эту технологию в личных целях, для наведения порядка в домашней инфраструктуре.

Достаточно часто приходится сливать информацию с медиа-носителей на десктоп/лаптоп/файловый сервер в попыхах, помещая ее куда-нибудь, лишь бы сохранить, с иллюзией о том, что скоро руки уж точно дойдут все разобрать в этот раз.

Было принято решение найти дубликаты фотографий и аудио данных, ввиду их большого объема и колосальной избыточности, растущей с каждой неделей.

 

Так как в моем случае речь идет о поиске дубликатов изображений и музыки, есть возможность (которой я конечно же воспользуюсь) не использовать хеширование ввиду больших расходов на вычисления хешей. Определение дубликата будет происходить на основе имени и размера файла.

 

Скрипт

Ниже я привожу написанный мной скрипт на bash, позволяющий осуществить дедупликацию по заданным параметрам.  

#!/bin/bash
path=$1         #Директория откуда осуществлять поиск
datafile="/tmp/datafile"        #Файл для хранения информации о необходимых файлах
find -P $path -type f -iregex '.*\.\(JPG\|JPEG\|RAW\|mp3\|wav\|flac\)' -exec du {} \; | sed 's/\(\/.*\/\)\(.*\)/\2\ \1\2/g'  |sed 's/\t/\ /g' >"$datafile"

cat /tmp/datafile |while read line
do
IFS=$(echo)     # Добавили разделитель
        p=$(echo $line | awk '{print $1" "$2}') #Выбрали из очередной строки размер и имя фала
        del="`(grep "$p" /tmp/datafile)`"       #Выбрали строки с идентичными файлами
        #echo $del|wc -l
        if [ $(echo $del|wc -l) -ne "1" ]       #Проверка на наличие дубликатов
                then
                count=0                 #Переменная для оставления первого файла
                first=""                        #Переменная для отображения первого файла
#                       for i in $del                   #Перебор идентичных файлов
        echo $del |while read i 
                        do
                        if [ $count -ne 0 ]     #Для оставления первого файла
                        then
                                deleted=$(echo $i |awk '{print $3}')
                                echo "File $deleted match with $first"                  #Уведомление о совпадающих файлах
                                echo $deleted |xargs rm -f                              #Удаление повторяющегося файла
                                tmp=$(grep -v $i         "$datafile")                   #Удаление из списка удаленного файла
                                echo $tmp>$datafile
                                ln -s $first $deleted                                   #Создание ссылки вместо файла
                        else
                                first=$(echo $i|awk '{print $3}')       #Запись эталонного (первого) файла
                                count=1
                                fi
                        done 
        fi
done;
~        

              

Для FreeBSD, ввиду небольших разностей синтаксиса 4 строка примет следующий вид

find -E $path -type f -iregex '.*\.(JPG|JPEG|RAW|mp3|wav|flac)' -exec du {} \; | sed 's/\(\/.*\/\)\(.*\)/\2\ \1\2/g'  |sed 's/\t/\ /g' >$datafile

Небольшие пояснения :

$path — место откуда будет осуществлен поиск файлов
Ключ P — не будет переходить по симлинкам
-iregex — позволяет использовать регулярные выражения (префикс i осуществляет поиск без учета регистра символов). В теле регулярного выражения указаны необходимые мне форматы файлов.
Sed используем для преобразования ввода в вид
размер          Имя файла               Полное имя файла
 
из вида 
размер  Полное имя файла
 
$datafile — файл в который запишется вывод нашей комманды
 
sed 's/\t/\ /g' — замена табуляции на пробел, для удобной дальнейшей работы.
Соответственно поиск будет осуществляться простым регулярным выражением по первым двум столбцам
 

P.S. Скрипт можно написать гораздо более оптимально, но я данную задачу не преследовал :-)