13

У меня есть сервер Debian, и я размещаю музыку для интернет-радиостанции. У меня проблемы с именами файлов и путями, потому что многие файлы имеют неправильную кодировку, например:

./music/Bändname - Some Title - additional Info/B�ndname - 07 - This Title Is Cörtain, The EncÃding Not.mp3

В идеале я хотел бы удалить все, кроме букв A-Z/a-z или цифр 0-9 или тире -/подчеркивания _ ... Результат должен выглядеть примерно так:

./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3

Как добиться этого для большого количества файлов и каталогов?

Я видел такой же вопрос: массовое переименование (или правильное отображение) файлов со специальными символами

Но это только исправляет кодировку, я бы предпочел более строгий подход, как описано выше.

3 ответа3

14

Я знаю, что это не совсем то, что вы хотели, но если вы знаете оригинальную кодировку, возможно, вы можете использовать convmv чтобы изменить кодировку на UTF-8, что должно решить большинство проблем.

Это сработало для меня в папке с некоторыми неверно закодированными польскими именами файлов:

convmv -f cp1250 -t utf8 -r .

Обратите внимание, что эта команда на самом деле ничего не переименовывает; добавить параметр --notest чтобы действительно переименовать файлы.

13

Вы столкнетесь с некоторыми проблемами, если хотите переименовать файлы и каталоги одновременно. Переименовать только файл достаточно просто. Но вы хотите убедиться, что каталоги также переименованы. Вы не можете просто mv Motörhead/Encöding Motorhead/Encoding так как Motorhead не будет существовать во время вызова.

Итак, нам нужно сначала просмотреть все файлы и папки, а затем переименовать только текущий файл или папку. Следующее работает с GNU find и Bash 4.2.42 на моей OS X.

#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
  d="$( dirname "$file" )"
  f="$( basename "$file" )"
  new="${f//[^a-zA-Z0-9\/\._\-]/}"
  if [ "$f" != "$new" ]      # if equal, name is already clean, so leave alone
  then
    if [ -e "$d/$new" ]
    then
      echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
      ls -ld "$d/$new" "$d/$f"
    else
      echo mv "$file" "$d/$new"      # remove "echo" to actually rename things
    fi
  fi
done

Вы можете изменить регулярное выражение, используя new="${f//[\\\/\:\*\?\"<>|]/}" если вы хотите заменить что-либо, что Windows не может обработать.

Сохраните этот скрипт как rename.sh , сделайте его исполняемым с помощью chmod +x rename.sh . Затем назовите его как rename.sh /some/path .

Обязательно разрешите любые конфликты имен файлов (« Notice »).

Если вы абсолютно уверены, что он делает правильные замены, удалите echo из сценария, чтобы фактически переименовать вещи, а не просто печатать то, что он делает.

Чтобы быть в безопасности, я бы рекомендовал сначала проверить это на небольшом подмножестве файлов.


Варианты объяснены

Чтобы объяснить, что здесь происходит:

  • -depth будет гарантировать, что каталоги рекурсивно проверяются на глубину, поэтому мы можем "свернуть" все с конца. Обычно find траверсы по-разному (но не в ширину).
  • -print0 гарантирует, что результат find будет разделен нулем, поэтому мы можем прочитать его с помощью read -d '' в file переменную. Это помогает нам справляться со всевозможными странными именами файлов, включая пробелы и даже переводы строк.
  • Мы получим каталог файла с dirname . Не забывайте всегда правильно указывать свои переменные в кавычках, иначе любой путь с пробелами или символами с пробелами сломает этот скрипт.
  • Мы получим фактическое имя файла (или имя каталога) с basename именем.
  • Затем мы удаляем любой недопустимый символ из $f используя возможности замены строк в Bash. Неверный означает все, что не является буквой в нижнем или верхнем регистре, цифрой, косой чертой (\/), точкой (\.), Подчеркиванием или минус-дефисом.
  • Если $f уже очищено (очищенное имя идентично текущему имени), пропустите его.
  • Если $new уже существует в каталоге $d (например, у вас есть файлы с именами resume и résumé в одном и том же каталоге), выведите предупреждение. Вы не хотите его переименовывать, потому что в некоторых системах mv foo foo вызывает проблемы.  Иначе,
  • Наконец мы переименовываем исходный файл (или каталог) в новое имя

Поскольку это будет действовать только в самой глубокой иерархии, переименование Motörhead/Encöding в Motorhead/Encoding выполняется в два этапа:

  1. mv Motörhead/Encöding Motörhead/Encoding
  2. mv Motörhead Motorhead

Это гарантирует, что все замены выполняются в правильном порядке.


Примеры файлов и тестовый прогон

Давайте предположим, что некоторые файлы находятся в базовой папке с именем test:

test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule

Вот результат выполнения в режиме отладки (с echo перед mv), то есть команды, которые будут вызваны, и предупреждения о столкновении:

mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r--  …  …  test/work/resume
-rw-r—r--  …  …  test/work/résumé

Обратите внимание на отсутствие сообщений для with-hyphen.txt , schedule и самого test .

0

Я знаю, вы спрашивали о переименовании.

Но вы можете легко избежать этой проблемы с помощью программного обеспечения, такого как MusicBrainz Picard.

Он способен идентифицировать музыку (аудио-дактилоскопию), загружать все необходимые данные (включая изображения обложек, если таковые имеются) из огромной базы данных MusicBrainz и перемещать файлы так, чтобы ваша коллекция могла соответствовать любому шаблону, который вам нравится. Я использую его годами, и он всегда отлично работал с любым языком, от кириллического до арабского; и, конечно (по крайней мере, для латинских скриптов), он также может выполнять преобразование в ASCII.

При таком подходе не имеет значения, насколько грязно / плохо названа ваша коллекция на самом деле, если файлы читаемы и полны.

(Я упоминал, что это бесплатно? И как в свободе слова, и как в свободном пиве? И программное обеспечение, и база данных ..?)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .