Você terá alguns problemas se quiser renomear arquivos e diretórios ao mesmo tempo. Renomear apenas um arquivo é fácil. Mas você deseja garantir que os diretórios também sejam renomeados. Você não pode simplesmente, mv Motörhead/Encöding Motorhead/Encodingpois Motorheadnão existirá no momento da ligação.
Portanto, precisamos de uma travessia profunda de todos os arquivos e pastas e renomear apenas o arquivo ou pasta atual. O seguinte funciona com o GNU finde o Bash 4.2.42 no meu 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
Você pode alterar a regex usando new="${f//[\\\/\:\*\?\"<>|]/}"se desejar substituir algo que o Windows não possa manipular.
Salve este script como rename.sh, torne-o executável com chmod +x rename.sh. Então, chame assim rename.sh /some/path.
Certifique-se de resolver qualquer colisão de nome de arquivo (" Notice" anúncios).
Se você tiver certeza absoluta de que faz as substituições corretas, remova echoo script para renomear as coisas em vez de apenas imprimir o que faz.
Para segurança, recomendo testar isso em um pequeno subconjunto de arquivos primeiro.
Opções explicadas
Para explicar o que se passa aqui:
-depthgarantirá que os diretórios sejam recursivos em profundidade primeiro, para que possamos "acumular" tudo do final. Geralmente, findpercorre de maneira diferente (mas não a largura).
-print0garante que a findsaída seja delimitada por nulo, para que possamos lê-la read -d ''na filevariável Isso nos ajuda a lidar com todos os tipos de nomes de arquivos estranhos, incluindo aqueles com espaços e até novas linhas.
- Obteremos o diretório do arquivo com
dirname. Não se esqueça de sempre citar suas variáveis corretamente, caso contrário, qualquer caminho com espaços ou caracteres brilhantes quebraria esse script.
- Obteremos o nome do arquivo real (ou nome do diretório) com
basename.
- Em seguida, removemos qualquer caractere inválido do
$fuso dos recursos de substituição de string do Bash. Inválido significa qualquer coisa que não seja uma letra maiúscula ou minúscula, um dígito, uma barra ( \/), um ponto ( \.), um sublinhado ou um hífen negativo.
- Se
$fjá estiver limpo (o nome limpo é idêntico ao nome atual), pule-o.
- Se
$newjá existir no diretório $d(por exemplo, você possui arquivos nomeados resumee résuméno mesmo diretório), emita um aviso. Você não deseja renomeá-lo porque, em alguns sistemas, mv foo foocausa um problema. De outra forma,
- Finalmente renomeamos o arquivo original (ou diretório) para seu novo nome
Como isso funcionará apenas na hierarquia mais profunda, a renomeação Motörhead/Encödingpara Motorhead/Encodingé feita em duas etapas:
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Isso garante que todas as substituições sejam feitas na ordem correta.
Arquivos de exemplo e execução de teste
Vamos assumir alguns arquivos em uma pasta base chamada 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
Aqui está a saída de uma execução no modo de depuração (com o echona frente do mv), ou seja, os comandos que seriam chamados e os avisos de colisão:
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é
Observe a ausência de mensagens para with-hyphen.txt, schedulee testem si.
mvjá existe, o que pode acontecer (1) se você tiver arquivos que já estão limpos (resultando emmv foo foo) ou (2) se você tiver arquivos com o mesmo nome, exceto para os caracteres especiais (por exemplo,mv Encöding Encodingonde você já possui umEncodingarquivo além deEncöding).