Ви зіткнетеся з деякими проблемами, якщо хочете одночасно перейменувати файли та каталоги. Перейменувати лише файл досить просто. Але ви хочете, щоб каталоги також були перейменовані. Ви не можете просто, 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виконується в два етапи:
mv Motörhead/Encöding Motörhead/Encoding
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саме по собі.
mvвже існує, що може статися (1), якщо у вас вже є чисті файли (в результатіmv foo foo), або (2), якщо у вас є файли з тим самим іменем, за винятком для спеціальних символів (наприклад,mv Encöding Encodingде у вас уже єEncodingфайлEncöding).