Sou TI na minha pequena empresa; e, apesar dos meus terríveis avisos, todos colocam arquivos no servidor com nomes horríveis, incluindo espaços iniciais e finais, caracteres ruins (incluindo \ ; / + . < > -
etc!)
Eles fazem isso acessando o servidor (FreeBSD/FreeNAS) via AFP em Macs, para que nenhuma parte do sistema reclame.
Existe um script que eu possa usar para percorrer uma árvore de diretórios inteira e corrigir nomes de arquivos incorretos?
Basicamente, substitua todos os espaços e ASCII incorretos por _
... e se um arquivo já existir, basta colocar um _2
ou algo assim no final.
Suponho que não haja uma maneira de fazer o sistema funcionarimporboas convenções de nomenclatura de arquivos, não é?
Obrigado!
Responder1
Eu usaria bash e encontraria. Tenho certeza de que há uma opção mais simples, mas aqui está o que eu descobri:
Isso pode lidar com nomes de arquivos contendo "/" (find dará um aviso, ignore-o), massó funcionará em arquivos no diretório atual(sem subdiretórios). Não consegui descobrir como diferenciar o bash ou find entre um "/" no nome de um arquivo e um "/" que faz parte do caminho.
for i in $(find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" | sed 's/\.\///'); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}; done
Estenão podelidar com nomes de arquivos contendo "/", mas funcionará em todos os arquivos no diretório atuale seus subdiretórios:
for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%]/_}; done
Tenha certeza deteste-os antes de executar. Eles funcionaram bem nos poucos testes que fiz, mas não fui exaustivo. Lembre-se também de que estou em um sistema Linux. A implementação específica de find, e talvez de bash, pode ser diferente da sua.
EDIT: Alterar o mv $i
comando para `mv -i $i' fará com que mv avise você antes de substituir 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 (adaptado deaqui):
SAVEIFS=$IFS; IFS=$(echo -en "\n\b"); for i in $(find . -type f -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%\ ]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%\ ]/_}; done; IFS=$SAVEIFS
Também modifiquei a expressão regular para combinar/substituir espaços por sublinhados. O bit SAVEIFS apenas retorna a variável IFS à 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, definindo sequencialmente a variável $i para cada um dos valores retornados pelo comando, e fará algo com ele.
find . -maxdepth 1 -type f -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" '
Encontre todos os arquivos no diretório atual cujo nome contenha um dos seguintes caracteres: :;><@$#&()\/%
. Para adicionar mais, basta escapar deles com "\" (por exemplo, "\¿") e adicioná-los à lista entre colchetes ([ ]). Provavelmente, nem todos esses caracteres precisam ser escapados, mas nunca consigo lembrar quais são variáveis especiais em qual ambiente, então escapei de tudo, só para garantir.
sed 's/\.\///
Remova o diretório atual da saída do find, imprima "foo" em vez de "./foo".
mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}
Cada vez que esse pequeno scipt fizer um loop, $i será o nome de um arquivo com nome incorreto. Este comando irá mover (renomear) esse arquivo alterando todos os caracteres indesejados para "_". Procure a substituição do bash para obter mais informações.