Есть ли более совершенный способ удаления дубликатов, чем fdupes -rdN?

Есть ли более совершенный способ удаления дубликатов, чем fdupes -rdN?

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

Рассмотрим команду fdupes -rdN somedirectory/. Она создает хеш всех файлов в подкаталогах somedirectory.

А когда он обнаруживает дубликаты, он их удаляет, так что остается только одна копия всего.

Но что делать, если я хочу сохранить somedirectory/subdirectory1/somefile, а на самом деле дубликатов четыре, и программа сначала встречает один из дубликатов? Затем она удаляет somedirectory/subdirectory1/somefile, чего я не хочу.

Я хочу иметь возможность указать, каким-то образом, какие дубликаты сохранять. И пока ни одна из стандартных программ для работы с дубликатами (duff, FSLint) не позволяет автоматизировать такое поведение. Я бы предпочел не заниматься собственными разработками, поэтому и задаю этот вопрос.

Я хотел бы иметь возможность написать что-то вроде

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/

решение1

Пока функционал, который вы ищете, отсутствует на складе fdupes, я разветвилfdupes (моя вилка называется jdupes)и добавили некоторые функции, которые могут решить эту проблему при определенных обстоятельствах. Например, в указанном случае, когда вы хотите сохранить somedirectory/subdirectory1/somefileпри автоматическом удалении дубликаты ( переключатели dи Nвместе) и нет отдельных файлов непосредственно под somedirectory, jdupesможно скормить каждому непосредственному пути подкаталога subdirectory1first и -Oпереключатель (который сортирует файлы по порядку параметров командной строки first):

jdupes -rdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Это автоматически удалит все файлы, кроме одного, в дублирующем наборе и гарантирует, что если набор содержит файл, то somedirectory/subdirectory1он будет первым, тем самым автоматически становясь сохраненным файлом в наборе. У этого подхода все еще есть явные ограничения, такие как тот факт, что другой дубликат somedirectory/subdirectory1может быть сохранен вместо того, который вы хотели сохранить, но в большом количестве случаев, таких как ваш, jdupesопция порядка параметров в качестве обходного пути достаточно хороша.

В ближайшем будущем я планирую добавить систему фильтрации, jdupesкоторая позволит осуществлять огромный контроль над включением/исключением файлов, сохранением для -Nдействий и применением таких «стеков фильтров» на глобальном уровне или на основе параметров. Эта функция крайне необходима; я представляю себе что-то вроде этого для «автоматического удаления ненулевых дубликатов рекурсивно, НО всегда сохранять somedirectory/subdirectory1/somefileкак есть»:

jdupes -rdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/

ОБНОВЛЕНИЕ (01.03.2022):Взгляните на -Xрасширенные параметры фильтров, добавленные в 2020 году. Это не совсем то, что вам нужно, но фильтры nostrи onlystrпозволяют указывать подстроки в полном пути, которые следует игнорировать или требовать.

решение2

Я не видел этого нигде: Скажите, что вы хотите это. У вас есть /mnt/folder-tree-1 /mnt/folder-tree-2. Вы не хотите удалять все дубликаты, но если файл существует в tree-2, и идентичный файл существует в tree-1 с точно таким же путем и именем, удалите его из tree-2.

Предупреждение: это довольно кратко, и если вы попытаетесь скопировать и вставить это, имея ограниченные навыки работы с оболочкой, будьте осторожны.

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt

fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line
do
if grep -q "`echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|'`" dupes-all.txt
then
    echo rm \"$(echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2//|')\"
fi
done > rm-v2-dupes.sh

Или все в одной строке:

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt; fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line; do if grep -q "`echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|'`" dupes-all.txt; then echo rm \"$(echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|')\"; fi; done > rm-v2-dupes.sh

После этого проверьте и выполните rm-v2-dupes.sh

решение3

А как насчет жесткого связывания дублирующихся файлов? Таким образом, пространство используется только один раз, но они все еще существуют во всех путях. Загвоздка в том, что жестко связанные файлы должны быть изменены на месте (они должны быть изменены только путем удаления файла и повторного создания его с новым содержимым). Другой подход заключается в том, чтобы создать символическую ссылку на файлы вместе, хотя у вас есть та же проблема с выбором «первичного» файла. Это можно сделать с помощью следующего скрипта (хотя обратите внимание, что он не обрабатывает имена файлов, содержащие пробелы).

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
    for DEST in $DESTS; do
        ln -f $SOURCE $DEST
    done
done

решение4

Просто чтобы добавить изюминку к предыдущему ответу. Я использовал следующий код несколько раз, немного изменив предыдущий ответ с помощью простого | grepспособа изолировать папку, из которой я хочу удалить.

`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`

Опять же, это создаст sh-файл для удаления всех перечисленных файлов, без закомментированных строк. Конечно, вы все равно можете редактировать файл, чтобы закомментировать определенные строки/файлы, которые вы хотите сохранить.

Еще один совет для больших каталогов — запустить fdupes в txt-файле, а затем экспериментировать с ним, | grepпока | sedне получу желаемый результат.

`fdupes -r -n -S /directory > duplicate-files.txt`
`cat duplicate-files.txt | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`

Связанный контент