segunda-feira, 3 de janeiro de 2011

Aplicando Comandos a vários Arquivos Recursivamente

Este artigo ensina como tirar proveito de uma famosa dupla: os comando find e xargs. Juntos, eles podem capturar arquivos que se encaixam em determinadas características e aplicar, de uma vez só, um comando específico para todos eles. É muito útil se você quiser apagar ou copiar determinados arquivos que existem em vários níveis diferentes da árvore de diretórios, contar linhas de um código que tem arquivos de fontes em vários diretórios dentro de uma pasta de fontes, além de milhares de outras coisas... Vejamos as possibilidades!!


  • O comando find

O segredo de tudo é o comando find. Basicamente, este comando é capaz de varrer o diretório especificado como parâmetro e todos os seus subdiretórios para achar e listar na tela arquivos que se conformem às características especificadas. Ele suporta duas ordens de parâmetros:

[1]- Configuração da busca (nível de profundidade, se deve ou não seguir links simbólicos, se deve ou não penetrar em outros filesystems montados na árvore pesquisada, se deve ser sensível à caixa ou não, etc...).
[2]- Configuração do filtro: quais as características dos arquivos que devem ser encontrados (nome ou trecho do nome do arquivo, data de modificação do arquivo maior ou menor que alguma data indicada, etc...).

Os parâmetros de [1] são sempre maiúsculos, e os parâmetros de [2] são sempre minúsculos. A documentação de todos os parâmetros pode ser fácil e detalhadamente encontrada na página de manual do comando (ou, opcionalmente, uma versão reduzida pode ser encontrada aqui). Para tanto, basta digitar:

man find

Assim, para não ficar muito teórico, vamos aprender a usar este comando a partir de exemplos, vendo como ele pode ser poderoso...


  • Encontrando Todos os .directory do Dolphin

O Dolphin, que vem por padrão com o KDE 4, é um excelente gerenciado de arquivos e realmente foi um bom substituto para quem subutilizava o Konqueror, no KDE 3, apenas como gerenciador de arquivos e pastas. O (grande?) problema dele e que, de fato, muito me incomoda, é que ele cria em diversos diretórios um arquivo oculto chamado ".directory". São arquivos de texto pequenos, contendo informações como a data do último acesso e o modo de visualização de arquivos. Um exemplo de arquivo ".directory":

cat .directory
[Dolphin]
Timestamp=2010,12,4,13,44,38
ViewMode=1

Se você é paranóico como eu e não gosta de deixar registros de onde você passou, ou simplesmente quer apagar estes arquivos para poupar espaço, vamos então primeiro encontrar a todos com o comando find, e depois apagá-los (quanto a apagá-los, continue conosco no item adiante...):

# Voltando para a pasta padrão do usuário
cd

# Encontrando recursivamente todos os arquivos ".directory"
find . -iname .directory

O que significa isso tudo no comando find?

".": diretório atual, a partir de onde a busca deve começar.
"-iname": indica que o filtro será por nome.
".directory": o nome do arquivo. Aqui podemos utilizar os mesmos caracteres curingas que usamos com todos os demais comandos de navegação e manipulação de arquivos.
O resultado será a listagem na tela do caminho a partir do diretório informado, linha a linha, de todos os arquivos encontrados.


  • Removendo Todos os .directory do Dolphin

Agora vamos finalmente apagá-los!! Para tanto, precisamos utilizar o comando xargs. Este comando simplesmente toma a saída de outro comando (como o find) e aplica seqüencialmente um terceiro comando, passado para ele por parâmetro, a cada linha que receber. O comando que apaga arquivos, como sabemos, é o "rm -f" (o parâmetro "-f" apenas assegura que o apagamento será silencioso, ou seja, o comando não vai te perguntar, item a item, se quer mesmo apagar o arquivo). É claro que o xargs tem várias opções e elas estão detalhadas na sua página de manual (digite "man xargs"). Para nós, o que interessa é que ele recebe como parâmetro o comando que deve ser executado para as benditas linhas do resultado.
Importante: para pegar a saída para a tela que o comando find gera e redirecioná-la para o comando xargs, utilize o caracter pipe ("|").
Assim, o comando mágico ficará:

find . -iname .directory | xargs rm -f

Outra opção, dispensando o comando xargs, é:

rm -f 'find . -iname .directory'

A única restrição é que os diretórios não podem ter nomes com caracteres inválidos (possível em alguns filesystems) ou com espaços, senão o comando rm falhará. Lembre-se de que o xargs passa para o comando que lhe foi informado a linha de resultado exatamente como ele a recebe!!


  • Apagando Todas as Pastas .svn

Cuidado com este comando, ele pode ser drasticamente perigoso, embora, em algumas situações, você possa querer isto mesmo....
Quem utiliza projetos versionados já deve ter notado que o cliente de versionamento adiciona geralmente uma pasta oculta com dados da versão local, dados temporários e, algumas vezes, algum cache de arquivos. Exemplos deste comportamento são o Subversion, que cria a pasta ".svn". Para remover estas pastas, use o comando:

find . -iname .svn | xargs rm -rf

A opção "-r" do comando rm apaga a pasta inteira mesmo que ela não esteja vazia, que certamente é o caso de uma pasta deste tipo acima.


  • Buscando Apenas Diretórios

find . -type d -name .sv*

A opção "-type d" indica que só estamos interessados em diretórios. Existem outros tipos que podem ser informados com o parâmetro "-type", a saber "f", para arquivo, "s", para soquete, "l", para link simbólico, etc.


  • Contando as Linhas de Vários Arquivos Fontes Automaticamente

Este é outro momento de glória do comando find!! Para contar as linhas de um arquivo, utilizamos o comando wc -l. O parâmetro "-l" indica que serão contadas apenas linhas.

find ./src -iname *.java | xargs wc -l

Note que, aqui, mostramos que os caracteres como "*" e "?" podem ser utilizados no comando find. Evidentemente, no comando acima, supomos que os arquivos fontes estão no diretório ./src.


  • Contando Todos os Arquivos de um Diretório

Se você quiser contar rapidamente todos os arquivos de um diretório, saiba que existem várias maneiras de se fazer isso, das quais podemos sugerir, com o comando find, uma maneira bem simples:

find . > arquivos && wc -l arquivos && rm arquivos

Dissecando o comando acima:

"find .": simplesmente lista todos os arquivos, já que nenhum filtro foi especificado.
"> arquivos": copia os resultados para um arquivo chamado "arquivos".
"&&": significa que outro comando deverá ser executado em seguida.
"wc -l arquivos": conta todas as linhas do arquivo "arquivos", ou seja, se a cada linha eu tenho, na verdade, um arquivo encontrado pelo comando find, então esta contagem corresponderá ao total de arquivos encontrados.
"&&": outro comando que deverá ser executado na seqüência...
"rm arquivos": claro, vamos apagar o arquivo "arquivos", já que ele foi criado apenas temporariamente para que o comando "wc -l" pudesse contar as suas linhas.

Assegure-se de ter permissão de escrita no local onde o arquivo será criado, para que o comando funcione!!
Este trecho é interessante porque pode dar margem a várias outras idéias (criando pesquisas específicas com os recursos que já vimos acima), como guardar em arquivos diferentes listagens específicas que poderão ser utilizadas em um script mais complexo, evitando repetir o comando find desnecessariamente.


Bom, pessoal, creio que vimos vários exemplos interessantes e muito úteis sobre como tirar proveito dos comandos find e xargs, uma verdadeira dupla dinâmica, usados em conjunto com os comandos wc, rm, dentre outros. Existem muitas outras situações interessantes derivadas destas e muitas outras novas, que podem ser formuladas de acordo com as suas criatividade e necessidade. O céu é o limite!! Espero que tenham gostado!! E não esqueçam que o Pajé adora quando os leitores COMENTAM!!!

2 comentários:

Gustavo Ferreira disse...

Ótimo artigo, resolveu o meu problema!

O Pajé disse...

Obrigado, Gustavo!!
Torço que o Pajé sempre consiga te ajudar a resolver problemas como este!!
Volte sempre!!