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