Поиск и удаление файлов с одинаковым префиксом, но другим расширением (например, * .flac и * .mp3)

В моем музыкальном каталоге есть несколько дубликатов файлов в формате .mp3 и .flac. Учитывать:

/dir1/music1.flac
/dir1/music1.mp3
/dir2/music1.mp3
/dir2/music2.MP3
/dir2/music2.flac
/dir2/music3.mp3

music1.flac и music1.mp3 в dir1 - это одна и та же песня в разных форматах, но music1.mp3 в dir1 и dir2 не могут быть (то же название, но выпущены на разных альбомах).

Я хочу пройти по нескольким подкаталогам, найти файлы с одинаковым префиксом, но с разными расширениями, а затем удалить только файлы mp3. Таким образом, для вышеуказанных каталогов у меня останется:

/dir1/music1.flac
/dir2/music1.mp3
/dir2/music2.flac
/dir2/music3.mp3

Я пытался использовать команду find с логическим И, но безуспешно. Некоторые неудачи с моей стороны:

find ./ -regex '.*\(mp3\|flac\)$'
find . -type f -name "*mp3" -and -name "*flac"

Любая помощь приветствуется. Я решил аналогичные проблемы с опубликованным кодом stackoverflow самостоятельно, но я в тупике. ВЫ, ПАРНИ, ОТЛИЧНЫЕ.


person doogie    schedule 11.01.2019    source источник
comment
В подобных вещах легко ошибиться и удалить больше, чем вы планировали. У тебя есть хорошая резервная копия?   -  person Gordon Davisson    schedule 11.01.2019
comment
У меня есть несколько резервных копий. Я понимаю риски.   -  person doogie    schedule 11.01.2019


Ответы (2)


Попробуйте этот (Shellcheck -clean) код:

#! /bin/bash

shopt -s nullglob   # Globs that match nothing expand to nothing
shopt -s globstar   # ** matches multiple directory levels

for mp3_path in **/*.[Mm][Pp]3 ; do
    # Find '.flac', '.FLAC', '.Flac', ..., files with the same base
    flac_paths=( "${mp3_path%.*}".[Ff][Ll][Aa][Cc] )
    if (( ${#flac_paths[*]} > 0 )) ; then
        # There is a(t least one) FLAC file so remove the MP3 file
        printf "Removing '%s'\\n" "$mp3_path"
        # rm -- "$mp3_path"
    fi
done

Для этого требуется Bash версии 4.0 или более поздней, поскольку он использует globstar.

Поскольку ваш пример включал как строчные, так и прописные '.mp3', код обрабатывает любой регистр '.mp3' или '.flac'. Его можно упростить, если в этом нет необходимости.

Удалите комментарий в строке rm, чтобы он действительно удалял файлы.

person pjh    schedule 11.01.2019
comment
@doogie, спасибо за отзыв. См. Что мне делать, когда кто-то ответит на мой вопрос?. - person pjh; 11.01.2019

Это подтвердит, что файлы будут удалены:

find . -type f|sort|awk -F ":" '{match($1,"(.+)\\.[A-Za-z0-9]+$",base); if (base[1]==prev) {fordel=$1} else {fordel=null};if (base[1]) prev=base[1]; if(fordel) {print "\"" fordel "\""}}'|xargs echo

И это обработает удаление:

find . -type f|sort|awk -F ":" '{match($1,"(.+)\\.[A-Za-z0-9]+$",base); if (base[1]==prev) {fordel=$1} else {fordel=null};if (base[1]) prev=base[1]; if(fordel) {print "\"" fordel "\""}}'|xargs rm

Оба решения будут обрабатывать пробелы в файлах.

person Borislav Markov    schedule 11.01.2019
comment
Спасибо за ваш вклад. Этот код работает с файлами без пробелов, но не может удалить пары файлов, такие как Christmas Song.mp3 и Christmas Song.flac - person doogie; 11.01.2019