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/Encoding
pois Motorhead
nã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 find
e 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 echo
o 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:
-depth
garantirá que os diretórios sejam recursivos em profundidade primeiro, para que possamos "acumular" tudo do final. Geralmente, find
percorre de maneira diferente (mas não a largura).
-print0
garante que a find
saída seja delimitada por nulo, para que possamos lê-la read -d ''
na file
variá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
$f
uso 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
$f
já estiver limpo (o nome limpo é idêntico ao nome atual), pule-o.
- Se
$new
já existir no diretório $d
(por exemplo, você possui arquivos nomeados resume
e résumé
no mesmo diretório), emita um aviso. Você não deseja renomeá-lo porque, em alguns sistemas, mv foo foo
causa 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öding
para 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 echo
na 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
, schedule
e test
em si.
mv
já 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 Encoding
onde você já possui umEncoding
arquivo além deEncöding
).