Как переименовать файлы с неправильной кодировкой или заменить недопустимые закодированные символы?

15

У меня есть сервер 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

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

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

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

Afr
источник

Ответы:

14

Вы столкнетесь с некоторыми проблемами, если хотите переименовать файлы и каталоги одновременно. Переименовать только файл достаточно просто. Но вы хотите убедиться, что каталоги также переименованы. Вы не можете просто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само по себе.

slhck
источник
1
Возможно, вы захотите добавить логику для обработки случая, когда место назначения mvуже существует, что может произойти (1), если у вас есть файлы, которые уже очищены (в результате mv foo foo), или (2), если у вас есть файлы с тем же именем, кроме для специальных символов (например, там mv Encöding Encoding, где у вас уже есть Encodingфайл в дополнение к Encöding).
Скотт
Хорошая идея, спасибо. Какие-то конкретные предложения о том, что делать в этом случае? Конечно, добиться этого чистым и разумным способом труднее, чем кажется на первый взгляд. Если у вас есть что-то, не стесняйтесь редактировать, конечно.
slhck
Я не верю, что имеет смысл задуматься об обработке коллизий автоматически - просто идентифицируйте их пользователю и позвольте ему справиться с ними. Я отредактировал ваш ответ, как вы предложили.
Скотт
+1 за использование примера с «Encöding». Слишком много для меня! :-)
Marcel
Через три года я все еще возвращаюсь сюда. так полезно! :-)
Афр
15

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

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

convmv -f cp1250 -t utf8 -r .

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

mik01aj
источник
1
Для тех, кто имеет статический набор (или не имеет разнообразного набора кодировок), этот convmvвариант удивительно прост и идеален. Для OP, имеющего потенциальное множество кодировок, это могло бы быть объединено с другим ответом, так как, convmvкажется, знает, когда он или когда он не встречает правильный формат. Циклически просматривая наборы символов, convmv --listможно было бы их правильно закодировать.
1
Под этим я подразумеваю, что если в качестве OP запускается сервер Debian, то в наши дни, безусловно, предполагается использование UTF8, и в этом случае можно сохранить исходные буквы. У меня была папка с несколькими нордическими символами, и я использовал: convmv -t utf8 --nfc -f iso-8859-1 --notest -r .- Это --nfcдолжно было соответствовать Linux, а не OS X или около того, просто ввод текста convmvотказался от (полезных) опций.
0

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

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

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

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

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

Алоис Махдал
источник