Script de shell para corrigir nomes de arquivos incorretos?

Script de shell para corrigir nomes de arquivos incorretos?

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 _2ou 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:

  1. 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
    
  2. 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 $icomando 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.


informação relacionada