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