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