Вопрос или проблема
Я пытаюсь найти все дублирующиеся файлы (по хешу MD5) и отсортировать их по размеру файла. Пока у меня есть следующее:
find . -type f -print0 | xargs -0 -I "{}" sh -c 'md5sum "{}" | cut -f1 -d " " | tr "\n" " "; du -h "{}"' | sort -h -k2 -r | uniq -w32 --all-repeated=separate
Вывод этого выглядит так:
1832348bb0c3b0b8a637a3eaf13d9f22 4.0K ./picture.sh
1832348bb0c3b0b8a637a3eaf13d9f22 4.0K ./picture2.sh
1832348bb0c3b0b8a637a3eaf13d9f22 4.0K ./picture2.s
d41d8cd98f00b204e9800998ecf8427e 0 ./test(1).log
Это самый эффективный способ?
Из xargs(1):
-I replace-str
… Предполагает -x и -L 1.
Так что это не самый эффективный способ. Было бы более эффективно, если бы вы просто передали как можно больше имен файлов в md5sum, что будет:
find . -type f -print0 | xargs -0 md5sum | sort | uniq -w32 --all-repeated=separate
В качестве альтернативы xargs
можно использовать (GNU) find(1) -exec (обратите внимание на знак плюс)
-exec command {} +
…
Командная строка строится аналогично тому, как xargs строит свои командные строки.
…
С этими альтернативами у вас, конечно, не будет размера файла. Если вам действительно нужен размер файла, создайте shell-скрипт, который выполняет md5sum
и du -h
и объединяет строки с помощью join
.
Иногда мы работаем с сокращенными наборами команд linux, такими как busybox или другими инструментами, которые идут с NAS и другими встраиваемыми Linux-устройствами (IoT). В этих случаях мы не можем использовать такие опции, как -print0
, из-за проблем с пространствами имен. Поэтому мы можем предпочесть вместо этого:
find | while read file; do md5sum "$file"; done > /destination/file
Тогда наш /destination/file
готов для любого рода обработки, такой как sort
и uniq
, как обычно.
Используйте либо btrfs + duperemove, либо zfs с онлайн-дедупликацией. Это работает на уровне файловой системы и будет сопоставлять даже равные части файлов, а затем использовать CoW файловой системы, чтобы оставить только одну из каждой, сохраняя файлы на месте. Когда вы изменяете одну из общих частей в одном из файлов, она будет записывать изменение отдельно. Таким образом, вы можете иметь такие вещи, как /media и /backup/media-2017-01-01, которые потребляют только размер каждой уникальной части информации в обоих деревьях.
Или вы можете использовать fdupes
:
fdupes -R /usr/share/doc | while read name; do \
test -n "$name" && \
size=`stat -c %s "$name" 2>/dev/null` && \
echo "$size $name"; \
done | sort -n
Ответ или решение
Чтобы выявить все дубликаты файлов на основе MD5-хеша и отсортировать их по размеру, можно использовать несколько подходов. Описание вашей текущей команды заслуживает того, чтобы его проанализировать и оптимизировать. Рассмотрим несколько методов, которые можно использовать для этой задачи.
Анализ текущего подхода
Ваша команда выглядит следующим образом:
find . -type f -print0 | xargs -0 -I "{}" sh -c 'md5sum "{}" | cut -f1 -d " " | tr "\n" " "; du -h "{}"' | sort -h -k2 -r | uniq -w32 --all-repeated=separate
Этот пример:
- Находит все файлы в текущей директории и поддиректориях.
- Вычисляет MD5-хэш для каждого файла.
- Получает размер файла с помощью
du -h
. - Сортирует результаты по размеру.
- Определяет дубликаты по MD5-хешам.
Хотя этот метод работает, он не является самым эффективным из-за использования xargs
и односвязного подхода к вызову md5sum
. Каждый файл обрабатывается отдельно, что увеличивает время выполнения.
Оптимизированный подход
Для улучшения производительности мы можем сгруппировать файлы и передать их в md5sum
одним командным вызовом:
find . -type f -print0 | xargs -0 md5sum | sort | uniq -w32 --all-repeated=separate
Этот подход позволяет передавать несколько файлов одновременно в md5sum
, что значительно уменьшает время выполнения. Однако вы не получаете информацию о размере файлов непосредственно с этим методом.
Включение размера файлов
Если вам необходимо также получить размер файлов, вы можете создать небольшую оболочку (shell-скрипт) для объединения информации о хешах и размерах:
find . -type f -print0 | xargs -0 md5sum | while read hash file; do
size=$(du -h "$file" | cut -f1) # Получаем размер файла в удобочитаемом формате
echo "$hash $size $file"
done | sort -k2 -hr | uniq -w32 --all-repeated=separate
Этот скрипт:
- Использует
find
иxargs
для получения MD5-хешей. - Для каждого файла в цикле
while
просматривается его размер. - Результаты сортируются по размеру и выводятся с соответствующими хешами.
Альтернативные инструменты
Если ваш рабочий характер ограничен стандартными утилитами или вы хотите более удобное решение, рассмотрите возможность использования fdupes
, которое автоматически находит дубликаты файлов:
fdupes -r . | while read name; do
size=$(stat -c %s "$name" 2>/dev/null)
echo "$size $name"
done | sort -n
Этот подход не только упрощает задачу нахождения дубликатов, но и позволяет учитывать размер файлов.
Вывод
Подход с использованием команды find
и xargs
является наиболее оптимизированным. Однако для получения информации о размере вам подойдет использование цикла для извлечения необходимых данных. Если вы работаете в среде с ограничениями, можно использовать более простые скрипты, которые совместят необходимые операции. Бесспорно, выбор подхода зависит от условий вашей работы, поэтому важно выбирать наиболее подходящие методы, основываясь на потребностях проекта и доступных инструментах.