Eu usaria bash e encontraria. Tenho certeza de que há uma opção mais simples, mas eis o que eu criei:
-
Isso pode lidar com nomes de arquivos que contenham "/" (a localização dará um aviso, ignore-a), mas funcionará somente em arquivos no diretório atual (sem subdiretórios). Eu não conseguia descobrir como dizer bash ou encontrar para diferenciar entre um "/" em um nome de arquivo e um "/" que faz parte do caminho.
for i in $(find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\/\%]*" | sed 's/\.\///'); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\/\%]/_}; done
-
Este não pode lidar com nomes de arquivos contendo "/", mas funcionará em todos os arquivos no diretório atual e em seus subdiretórios :
for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\%]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\%]/_}; done
Certifique-se de testar estes antes de executar . Eles funcionaram bem nos poucos testes que eu fiz, mas eu não estava exaustivo. Também tenha em mente que estou em um sistema linux. A implementação específica do find, e talvez do bash, pode diferir da sua.
EDIT: Alterar o comando mv $i
para 'mv -i $ i' fará com que o mv avise antes de sobrescrever um arquivo existente.
EDIT2: Para lidar com nomes de arquivos com espaços, você pode alterar a variável bash IFS (Input Field Separator) assim (adaptada de aqui ):
SAVEIFS=$IFS; IFS=$(echo -en "\n\b"); for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\%\ ]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\%\ ]/_}; done; IFS=$SAVEIFS
Eu também modifiquei a expressão regular para corresponder / substituir espaços com sublinhados. O bit SAVEIFS apenas retorna a variável IFS para sua configuração original.
EXPLICAÇÃO:
for i in $(command); do something $i; done
Este é um loop bash genérico. Ele passará pela saída de um comando, configurando sequencialmente a variável $ i para cada um dos valores retornados pelo comando e fará algo com ela.
find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\/\%]*" '
Encontre todos os arquivos no diretório atual cujo nome contenha um dos seguintes caracteres: :;><@$#&()\/%
. Para adicionar mais, apenas escape com "\" (por exemplo, "\") e adicione-os à lista entre colchetes ([]). Provavelmente, nem todos esses caracteres precisam ser escapados, mas eu nunca consigo lembrar quais são variáveis especiais em qual ambiente, então eu escapei de tudo, apenas no caso.
sed 's/\.\///
Remova o diretório atual da saída do find, imprima "foo" em vez de "./foo".
mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\/\%]/_}
Toda vez que esse pequeno scipt fizer um loop, $ i será o nome de um arquivo mal-nomeado. Este comando irá mover (renomear) aquele arquivo mudando todos os caracteres indesejados para "_". Procure por substituição de bash para mais informações.