Find: buscando arquivos com critérios complexos

1. Introdução ao find e sua sintaxe fundamental

O comando find é uma das ferramentas mais poderosas do ecossistema Unix/Linux para localizar arquivos e diretórios com base em critérios complexos. Sua sintaxe fundamental segue o padrão:

find [caminho] [expressão]

Diferentemente de locate, que consulta um banco de dados indexado, o find realiza uma busca em tempo real percorrendo a árvore de diretórios. Enquanto grep busca conteúdo dentro de arquivos, find localiza os próprios arquivos por suas propriedades.

Os predicados no find se dividem em duas categorias principais:
- Testes: condições que retornam verdadeiro ou falso (ex: -name, -type)
- Ações: operações executadas quando um teste é satisfeito (ex: -print, -exec)

2. Filtros por tipo, nome e tamanho

A filtragem por tipo de arquivo utiliza o parâmetro -type:

find /var/log -type f          # apenas arquivos regulares
find /home -type d             # apenas diretórios
find /usr -type l              # apenas links simbólicos

Para nomes, usamos -name com curingas (case sensitive) e -iname (case insensitive):

find /etc -name "*.conf"       # todos os .conf em /etc
find /docs -iname "relatorio*" # Relatorio, RELATORIO, etc.
find / -path "*/src/*.c"       # busca pelo caminho completo

Critérios de tamanho são extremamente úteis:

find / -size +100M             # arquivos maiores que 100MB
find . -size -1k               # arquivos menores que 1KB
find /tmp -size 0              # arquivos vazios

As unidades disponíveis incluem c (bytes), k (kilobytes), M (megabytes), G (gigabytes).

3. Filtros por tempo e permissões

O find oferece controle granular sobre timestamps:

find /var -mtime -7            # modificados nos últimos 7 dias
find /home -atime +30          # acessados há mais de 30 dias
find /backup -ctime 0          # status alterado hoje

Para buscas mais precisas em minutos:

find /tmp -mmin -60            # modificados na última hora
find /logs -amin +120          # não acessados há 2 horas
find /cache -cmin -5           # status alterado nos últimos 5 min

Permissões e propriedade:

find /usr -perm 644            # permissões exatas
find /etc -perm -4000          # arquivos com SUID ativado
find /home -user joao          # pertencentes ao usuário joao
find / -group admin            # pertencentes ao grupo admin
find / -nouser                 # órfãos (sem dono no sistema)

4. Operadores lógicos e combinação de testes

Os operadores lógicos permitem construir critérios complexos:

# AND implícito (padrão entre testes)
find . -type f -name "*.log"

# AND explícito com -a
find . -type f -a -name "*.tmp"

# OR com -o
find . -name "*.jpg" -o -name "*.png"

# Negação com ! ou -not
find . ! -type d               # tudo que não é diretório
find . -not -user root         # arquivos não pertencentes a root

# Agrupamento com parênteses escapados
find . \( -name "*.txt" -o -name "*.md" \) -type f

Os parênteses devem ser escapados com \ para evitar interpretação pelo shell.

5. Executando ações sobre os resultados

A ação padrão do find é -print. Para lidar com nomes contendo espaços:

find . -name "*.pdf" -print          # saída padrão
find . -name "*.pdf" -print0         # separado por null (seguro)

O -exec permite executar comandos nos resultados:

# Com \; (executa uma vez por arquivo)
find . -name "*.bak" -exec rm {} \;

# Com + (agrupa argumentos, mais eficiente)
find . -name "*.log" -exec gzip {} +

O -execdir executa o comando no diretório do arquivo encontrado:

find /var/log -name "*.gz" -execdir ls -la {} +

6. Otimização e boas práticas em scripts

Para evitar problemas com espaços e caracteres especiais, a combinação -print0 com xargs -0 é essencial:

find /mnt -name "*.mp3" -size +10M -print0 | xargs -0 -I {} cp {} /backup/

Loops seguros com while read:

find . -type f -name "*.txt" -print0 | while IFS= read -r -d '' arquivo; do
    echo "Processando: $arquivo"
    wc -l "$arquivo"
done

Controle de profundidade evita buscas desnecessárias:

find / -maxdepth 3 -name "*.conf"    # máximo 3 níveis
find /app -mindepth 2 -type d        # ignora os 2 primeiros níveis

7. Casos práticos e exemplos combinados

Exemplo 1: Encontrar arquivos grandes (>500MB) não acessados há 30 dias

find / -type f -size +500M -atime +30 -exec ls -lh {} \; 2>/dev/null

Exemplo 2: Localizar diretórios vazios e removê-los com confirmação

find /tmp -type d -empty -exec rm -d -i {} +

Exemplo 3: Buscar logs antigos e compactar

find /var/log -name "*.log" -mtime +7 -exec gzip -v {} \;

Exemplo 4: Encontrar e listar detalhes de arquivos com permissões especiais

find /usr/bin -perm /4000 -o -perm /2000 | xargs ls -la

Exemplo 5: Script completo para limpeza de arquivos temporários

#!/bin/bash
# Remove arquivos .tmp com mais de 3 dias do diretório /tmp

find /tmp -name "*.tmp" -type f -mtime +3 -print0 | while IFS= read -r -d '' arq; do
    echo "Removendo: $arq"
    rm -f "$arq"
done

Referências