Як групово перейменувати файли з недійсним кодуванням або масово замінити недійсні кодовані символи?


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

Як цього досягти для партії багатьох файлів і каталогів?

Я бачив таке подібне питання: групове перейменування (або правильне відображення) файлів зі спеціальними символами

Але це лише виправляє кодування, я вважаю за краще більш суворий підхід, як описано вище.

Відповіді:


14

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

Отже, нам потрібна перша глибина обходу всіх файлів і папок, а потім перейменування лише поточного файлу чи папки. Наступні роботи з GNU findта Bash 4.2.42 на моїй ОС 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використанням можливостей заміни рядків Баша. Недійсне означає все, що не є малою чи малою літерою, цифрою, косою рисою ( \/), крапкою ( \.), підкресленням або мінус-дефісом.
  • Якщо $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саме по собі.


1
Ви можете додати логіку для обробки випадку, коли призначення mvвже існує, що може статися (1), якщо у вас вже є чисті файли (в результаті mv foo foo), або (2), якщо у вас є файли з тим самим іменем, за винятком для спеціальних символів (наприклад, mv Encöding Encodingде у вас уже є Encodingфайл Encöding).
Скотт

Гарна ідея, дякую. Якісь конкретні пропозиції щодо того, що робити в такому випадку? Зрозуміло - досягти цього в чистому та здоровому порядку важче, ніж здається спочатку. Якщо у вас щось є, сміливо редагуйте курс.
slhck

Я не вірю, що має сенс думати про поводження зіткненнями автоматично - просто визначте їх з користувачем і дозвольте йому впоратися з ними. Я відредагував вашу відповідь, як ви запропонували.
Скотт

+1 за використання прикладу з "Encöding" Занадто багато fön !:-)
Marcel

Через три роки я все ще повертаюся сюди. так корисно! :-)
Waqar Lim

15

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

Це працювало для мене в папці з деякими кодованими недійсними польськими іменами:

convmv -f cp1250 -t utf8 -r .

Зауважте, що ця команда насправді нічого не перейменовує; Додати --notestопцію, щоб дійсно перейменувати файли.


1
Для тих, хто має статичний набір (або не має різноманітного поєднання шаблонів), convmvваріант надзвичайно простий та ідеальний. Для ОП, що має потенційну кількість шаблонів, це може бути об'єднано з іншою відповіддю, оскільки, convmvсхоже, відомо, коли це чи коли воно не відповідає правильному формату. Переглядаючи шаблони через convmv --list, можна було б їх правильно закодувати.

1
Під цим я маю на увазі, якщо, як ОП працює сервер Debian, сьогодні, звичайно, можна було б вважати UTF8, і в цьому випадку можна зберегти оригінальні листи. У мене була папка деяких нордичних символів, і я використовував: convmv -t utf8 --nfc -f iso-8859-1 --notest -r .- Потрібно --nfcбуло відповідати Linux перед ОС X або близько того, просто ввівши, convmvвипускаєте (корисні) параметри.

0

Я знаю, ви запитували про перейменування.

Але ви можете уникнути проблеми досить легко, використовуючи таке програмне забезпечення, як MusicBrainz Picard .

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

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

(Я згадав, що це безкоштовно? І як у вільній мові, і як у вільному пиві? І програмне забезпечення, і база даних ..?)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.