Я бы использовал Bash и найти. Я уверен, что есть более простой вариант, но вот что я придумал:
Это может иметь дело с именами файлов, содержащими «/» (команда find выдаст предупреждение, проигнорирует его), но будет работать только с файлами в текущем каталоге (без подкаталогов). Я не мог понять, как сказать bash или найти различие между "/" в имени файла и "/", который является частью пути.
for i in $(find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" | sed 's/\.\///'); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}; done
Этот не может работать с именами файлов, содержащими «/», но он будет работать со всеми файлами в текущем каталоге и его подкаталогах:
for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%]/_}; done
Обязательно проверьте их перед запуском. Они работали хорошо в тех нескольких тестах, которые я проводил, но я не был исчерпывающим. Также имейте в виду, что я в системе Linux. Конкретная реализация find и, возможно, bash может отличаться от вашей.
РЕДАКТИРОВАТЬ: изменение команды mv $i
на `mv -i $ i 'заставит mv запросить у вас перезапись существующего файла.
РЕДАКТИРОВАТЬ 2: Чтобы иметь дело с именами файлов с пробелами, вы можете изменить переменную bash IFS (Разделитель входных полей) следующим образом (адаптировано здесь):
SAVEIFS=$IFS; IFS=$(echo -en "\n\b"); for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%\ ]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%\ ]/_}; done; IFS=$SAVEIFS
Я также изменил регулярное выражение, чтобы сопоставить / заменить пробелы подчеркиванием. Бит SAVEIFS просто возвращает переменную IFS в исходную конфигурацию.
ОБЪЯСНЕНИЕ:
for i in $(command); do something $i; done
Это общий цикл bash. Он будет проходить через вывод команды, последовательно устанавливая переменную $ i для каждого из значений, возвращаемых командой, и будет что-то с ней делать.
find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" '
Найти все файлы в текущем каталоге, имя которых содержит один из следующих символов :;><@$#&()\/%
. Чтобы добавить больше, просто экранируйте их с помощью «\» (например, «\¿») и добавьте их в список в квадратных скобках ([]). Возможно, не все эти символы нужно экранировать, но я никогда не могу вспомнить, какие специальные переменные в какой среде, поэтому я избегаю всего, на всякий случай.
sed 's/\.\///
Удалите текущий каталог из результатов поиска, напечатайте "foo" вместо «./foo».
mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}
Каждый раз, когда этот маленький цикл scipt, $ i будет именем файла с плохим именем. Эта команда переместит (переименует) этот файл, изменив все ненужные символы на "_". Посмотрите замену bash для получения дополнительной информации.