Após ver sobre o comando find no nosso canal Papo Binário decidi estudar um pouco mais sobre o mesmo. Revisando estas anotações pensei que seria interessante compartilhá-las, tendo em vista que o find é um comando extremamente poderoso. Alguns dos parâmetros já foram abordados no vídeo, mas vou repassar alguns aqui, não custa nada, não é mesmo?!
Este comando pode ser útil para diversas tarefas, dentre elas investigação, administração ou mesmo aprendizado sobre o sistema.
Indo direto ao ponto, o find é um comando para procurar itens no filesystem (arquivos, links, diretórios, etc). O que o difere de outros programas que fazem isto é a quantidade de opções que a ferramenta possui e o fato de não depender da variável $PATH para encontrar um binário. O comando leva como principal parâmetro um path, ou seja, um caminho para procurar algo. Se não passarmos nada ele entenderá que o path é o diretório atual:
find
find /etc
Se não especificarmos exatamente o que queremos buscar o find simplesmente nos mostra tudo o que achar pois ele varre o filesystem recursivamente na hora de procurar algo, mas não queremos isso tudo, até porque não seria muito útil. ?
Vamos tentar entender alguns filtros interessantes... Imagine que você é um administrador e precisa verificar todos os arquivos que pertencem a um usuário em específico:
find / -type f -user leandro
O que fizemos aqui? Utilizamos 2 tipos de filtros, um deles foi o -user, que busca arquivos que pertencem apenas à aquele usuário. O -type filtra pelo tipo de item no filesystem e suporta os seguintes tipos:
-
d -> diretório
-
f -> arquivo regular
-
l -> link simbólico
-
s -> socket
find . -mindepth 2 -name "*mentebinaria*" -type fA primeira coisa que fizemos foi utilizar a opção -mindepth, que especifica quantos níveis na hierarquia o find deve olhar no mínimo (a opção -maxdepth especifica o máximo). A outra opção foi a -name, que procura por um nome completo ou parte dele como fizemos no exemplo utilizando o wildcard * (asterisco) para bater com qualquer string antes de depois da palavra "mentebinaria".
Executando comandos:
Na minha opinião uma das opções mais interessantes do find é a -exec, que praticamente executa comandos em cima do que o find encontrar. Não entendeu? Vamos lá... supondo que queiramos ver qual o tipo de arquivo de todos os arquivo que encontrarmos em um diretório em específico com o comando file:
find . -type f -exec file {} \;
Temos muita coisa pra entender nesta linha. Primeiro, o -exec trabalha com o conceito de targets (as chaves {} ) e isto significa: coloque tudo o que o find devolver no local da chave. Para cada arquivo que o find achar ele rodará o comando file naquele arquivo. Incrível, não?
Sim, mas com isto estaremos executanto o mesmo comandos múltiplas vezes, por exemplo:
leandro@teste:~$ find . -type f | wc -l 295
Imagine rodar isto 295 vezes, muita coisa, não? Se notarmos no primeiro exemplo do -exec vemos que no fim da linha tem um ponto de vírgula e este indica o fim do -exec para o find (e não para o shell). Temos que usar a contra barra para escapar e o shell não pensar que é para ele.
Ok, mas até agora não vimos como melhorar isto. Concordam que o comando file aceita mais de um parâmetro?
file arq1 arq2 arq3
E se pudéssemos pegar tudo que o find achar e, ao invés de rodar um comando do -exec por vez passamos tudo um atrás do outro? É exatamente isto o que o + faz e para ele não precisamos escapar:
find . -type f -exec file {} +
Este exemplo é a mesma coisa do anterior, mas de forma mais automatizada. Vamos medir a velocidade dos dois comandos:
root@teste:~# time find / -type l -exec file {} \; ... real 0m15,127s user 0m0,336s sys 0m1,640s
root@teste:~# time find / -type l -exec file {} + ... real 0m1,119s user 0m0,212s sys 0m0,396s
Bem mais rápido com o +, não acham? ?
Investigando o sistema:
Seu servidor foi atacado, você não sabe exatamente o que aconteceu e como aconteceu, só sabe que nem tudo está funcionando do jeito que deveria. Uma coisa interessante à se fazer é tentar olhar para o que exatamente foi alterado desde o ataque. Imagine que isto ocorreu à 2 dias:find / -mtime -2
Aqui estamos dizendo que a partir da hora que rodarmos o comando olhar para tudo que foi modificado 48 horas atrás. Podemos também verificar se algo foi acessado com -atime.
E se você não sabe exatamente quando foi o ataque? A única coisa que você sabe é que a última coisa que você fez foi adicionar novas funcionalidades à um script que você tem. Podemos procurar por tudo que foi modificado após este arquivo com a opção -newer:
find /etc -newer <arquivo_velho>
Mas como isto? O Linux guarda um tipo de informação chamada MAC no inode de cada arquivo, resumindo é simplesmente a data da última modificação, acesso e criação do arquivo ao qual aquele inode se refere. Apenas como curiosidade, o comando stat lê essas informações também. ?
Mais algumas informações:
Ok, agora você não teve nenhum problema, só quer algumas informações sobre os arquivos que o find encontrar. A opção -size <n> pode ajudar a procurar por arquivos maiores (+) ou menores (-) que o especificado:
find /var -size +20k
Podemos trabalhar com os seguintes formatos:
-
c -> bytes
-
k -> KB
-
0 ou -empty -> vazio
find . -empty
Não está satisfeito? Ok, a opção -ls ti da muito mais informações (praticamente aplica um ls -lids em cima de tudo que o find achar)
find . -user leandro -type d -ls
Facilitando o parsing:
Achou as opções de informações fracas? De fato a saída fica bem poluída. E se você precisasse todo dia monitorar informações específicas sobre arquivos específicos e criasse um script para isso, como você faria para obter estas informações? O find ti ajuda nisso também!!! Se você está familiarizado com a linguagem C (se não está veja isto) a função printf do C pode imprimir uma saída formatada de acordo com o que você escolher (string, inteiro, inteiro sem sinal, etc).
Assim como em C, a opção -printf possui uma série de diretivas para formatarmos a saída do find como quisermos, algumas delas são:
- %f -> nome do arquivo
- %p -> path completo
- %i -> inode
- %M -> permissões
- %n -> número de hard links
find / -type f -atime -1 -printf '%p %i %M \n'
O único detalhe aqui é que por padrão o -printf não coloca um caractere de nova linha, devemos adicionar como no exemplo. Com isto a saída fica bem mais interesante para um script ler, não acham?! Aqui está o exemplo de uma saída:
file1 262295 -rw-r--r-- file2 262283 -rw-r--r-- file3 262296 -rw-r--r--
Estas foram algumas dicas sobre o comando find. Com certeza informações mais completas podem ser encontradas no manual do comando, este tutorial tem como objetivo simplesmente compartilhar minhas anotações sobre o que acho bem interessante e usual sobre o comando find.
Qualquer dúvida, crítica ou sugestão, por favor, sinta-se à vontade para comentar e obrigado! ?