quinta-feira, 11 de agosto de 2011

Renomeando diretórios e arquivos recursivamente

  Depois de fazer um certo curso, fui ver a documentação que recebi e os nomes dos arquivos estavam em letras maiúsculas e espaços. Resolvi organizar de forma que estejam com letras minúsculas e sem espaço.
  Primeiro tratei dos nomes dos diretórios e subdiretórios. Observe que o comando find find -type d encontra os diretórios a partir de onde foi dado o comando.
Nota: o comando ls -l mostra os detalhes. Se o primeiro caracter é d, é um diretório. Se for um - é um arquivo comum.
  Tudo que é encontrado é redirecionado para o arquivo /tmp/files_diretorios.txt através do caracter >.
  Em seguida, a variável total_diretorios armazena a quantidade de diretórios. Essa informação é passada para o laço for que avança linha por linha através da combinação de head e tail. A variável Maiuscula guarda o nome original do arquivo buscando dentro do arquivo /tmp/files_diretorios.txt enquanto que minuscula armazena o mesmo nome, porém trocando de maiúscula para minúscula através do comando tr. Uma vez obtido o nome original e o nome personalizado, o comando mv renomeia o que está na primeira variável para a segunda. Extremamente importante as aspas porque os nomes dos arquivos geralmente possuem espaços.   Para remover o espaço, a saída do comando echo é a entrada do comando sed que interpreta 's/ //g' para substituir espaços por nada de forma global (observe a letra g).
  Terminado o tratamento para os diretórios, é a vez de levantar os arquivos comuns. O comando find -type f > /tmp/files_arquivos.txt busca todos arquivos e armazena no arquivo /tmp/files_arquivos.txt (reforçando, o levantamento é feito a partir de onde foi dado o comando).

#!/bin/bash

find -type d > /tmp/files_diretorios.txt
total_diretorios=`wc -l /tmp/files_diretorios.txt | cut -f1 -d' '`

for i in `seq $total_diretorios`
  do
   Maiuscula=`head -n $i /tmp/files_diretorios.txt | tail -n 1`
   minuscula=`head -n $i /tmp/files_diretorios.txt | tail -n 1 | tr A-Z a-z`
   mv -v "$Maiuscula" "$minuscula"
   sem_espaco=`echo $minuscula | sed 's/ //g'`
   mv -v "$minuscula" "$sem_espaco"
  done

find -type f > /tmp/files_arquivos.txt
total_arquivos=`wc -l /tmp/files_arquivos.txt | cut -f1 -d' '`

for i in `seq $total_arquivos`
  do
   Maiuscula=`head -n $i /tmp/files_arquivos.txt | tail -n 1`
   minuscula=`head -n $i /tmp/files_arquivos.txt | tail -n 1 | tr A-Z a-z`
   mv -v "$Maiuscula" "$minuscula"
   sem_espaco=`echo $minuscula | sed 's/ //g'`
   mv -v "$minuscula" "$sem_espaco"
  done

  Para um demonstração, digitei o comando abaixo dentro do diretório /tmp e veja a quantidade de diretórios e arquivos para organizar:

$ wc -l file*
377 files_arquivos.txt
56 files_diretorios.txt
433 total
  Para saber quanto tempo levou a execução do script, usa-se o comando time seguido no nome do seu script. Eu dei o nome de organiza.sh.

time ./organiza.sh

  E a resposta foi:

0m6.396s

  Apenas 6 segundos e 396 milésimos de segundo!

  Aproveitando a oportunidade, gostaria de introduzir o uso de funções. O conceito é simples. Se em outra parte do código realiza a mesma tarefa, este bloco de instruções pode ser atribuído um nome e delimitado por chaves ({}). A função deve ser codificada antes da função chamada. O código abaixo mostra uma versão enxuta usando funções. Uma diferença é que o armazenamento das informações vão para o arquivo /tmp/files.txt em vez de separar em dois arquivos. Não há problema porque primeiro trata de todos os diretórios e só então começa o processo de alterar os nomes de arquivos.

#!/bin/bash

tratamento()
{
   Maiuscula=`head -n $i /tmp/files.txt | tail -n 1`
   minuscula=`head -n $i /tmp/files.txt | tail -n 1 | tr A-Z a-z`
   mv -v "$Maiuscula" "$minuscula"
   sem_espaco=`echo $minuscula | sed 's/ //g'`
   mv -v "$minuscula" "$sem_espaco"
}

find -type d > /tmp/files.txt
total_diretorios=`wc -l /tmp/files.txt | cut -f1 -d' '`

for i in `seq $total_diretorios`
  do
   tratamento
  done

find -type f > /tmp/files.txt
total_arquivos=`wc -l /tmp/files.txt | cut -f1 -d' '`

for i in `seq $total_arquivos`
  do
   tratamento
  done

  Seja visualizar no modo texto ou no modo gráfico (usando nautilus, por exemplo), eu gosto que os arquivos sigam um padrão. Por isso, nada melhor do que um pouco de script para fazer um serviço trabalhoso em poucos segundos!
  Foi uma boa oportunidade para mostrar funções que é comum às linguagens de programação. Entendendo o conceito, é fortemente recomendado o seu uso, pois garante que as tarefas serão executadas todas da mesma forma.

Nenhum comentário:

Postar um comentário