Я хотел бы написать скрипт, который находит дубликаты mp3 по контенту, а не по имени файла bf. Мне интересно, как один идет о том, чтобы видеть внутренние типы файлов для сравнения. Спасибо.идентификация .mp3 не по имени с помощью сценария оболочки
ответ
cmp
может использоваться для сравнения двоичных файлов.
cmp file1.mp3 file2.mp3
if [[ $? -eq 0 ]]; then echo "Matched"; fi
cmp
команда возвращает 0
если файлы одинаковые или еще -1
.
Если файлы действительно байт-байт-эквивалент, вы можете начать поиск файлов того же размера. Если их размер один и тот же, вы можете продолжить исследование (например, сравнить их md5sum
). Если файлы содержат только одну песню, но используют другой кодек/сжатие/все, bash, вероятно, не подходит для этой задачи.
haha спасибо, мой следующий вопрос будет, если есть какой-либо подход с использованием хеш-карт. – slev
Я использую этот скрипт для своей фотографии, но его можно использовать для других файлов.
- Сначала я передать фотографии из моих телефона/камер в каталог
newfiles
- Затем я запускаю этот скрипт из моих фотографий корневого каталога
- При обнаружении дублированных файлов, скрипт сохраняет один файл и перемещает другие из них в каталог
../garbage
- сценарий движется в приоритетном файле из
newfiles
- При обнаружении дублированных файлов, скрипт сохраняет один файл и перемещает другие из них в каталог
Внимание: Этот скрипт не сравнивает содержимое файла, но он обнаруживает файлы с одинаковым размером & (это нормально для файлов камеры). Мой другой ответ основан на сравнении содержания (md5sum
).
#!/bin/bash
# If a file from directory 'newfile' has same size & name
# that another file from another directory
# then moves the file from 'newfile' to 'garbage'
find newfiles/ -type f -printf '%s %f\n' |
while read SIZE f
do
find . -name "$f" -size ${SIZE}c |
grep -v 'newfiles' &&
find . -name "$f" -size ${SIZE}c -path '*newfiles*' -exec mv -v '{}' ../garbage ';' &&
echo
done
# Detect all other duplicated files
# Keep the first occurrence and moves all other to 'garbage'
find . -type f -printf '%s %f\n' |
LC_ALL=C sort | #LC_ALL=C disables locale => sort is faster
uniq -dc | #keep duplicates and count number of occurrences
while read n SIZE f
do
echo -e "\n_____ $n files\t$SIZE bytes\tname: $f"
find . -name "$f" -size ${SIZE}c |
head -n 1 |
xargs mv -v -t ../garbage
done
Это первый из командной строки перечислены все файлы, имеющие одинаковый размер и тот же md5sum
из текущего каталога
find . -type f -printf '%11s ' -exec md5sum '{}' ';' |
sort | uniq -w44 --all-repeated=separate
Вторая командная строка
- быстрее, потому что он вычисляет
md5sum
исключительно для файлов с одинаковым размером - надежнее, поскольку он обрабатывает имена файлов, имеющих специальные символы, как «пространство» или «перевод строки»
Поэтому он также более сложный
find . -type f -printf '%11s %P\0' |
LC_ALL=C sort -z |
uniq -Dzw11 |
while IFS= read -r -d '' line
do
md5sum "${line:12}"
done |
uniq -w32 --all-repeated=separate |
tee duplicated.log
Некоторые объяснения
# Print file size/md5sum/name in one line (size aligned in 11 characters)
find . -printf '%11s ' -exec md5sum '{}' ';'
# Print duplicated lines considering the the first 44 characters only
# 44 characters = size (11 characters) + one space + md5sum (32 characters)
uniq -w44 --all-repeated=separate
# Print size and path/filename terminated by a null character
find . -printf '%11s %P\0'
# Sort lines separated by a null character (-z) instead of a newline character
# based on native byte value (LC_ALL=C) instead of locals
LC_ALL=C sort -z
# Read lines separated by null character
IFS= read -r -d '' line
# Skip the first 12 characters (size and space)
# in order to obtain the rest: path/filename
"${line:12}"
благодарственное вы это прекрасно. Если бы я решил адаптировать мой код для сравнения всех типов файлов, могу ли я сделать что-то с вложенным циклом для сравнения всех файлов с помощью опции -t? – slev
@slev Какой вариант '-t'? –