Guida pratica a find in Bash

find è l’utility standard per cercare file e directory su sistemi Unix-like. È potentissima: filtra per nome, tipo, dimensione, permessi, date, contenuti, e può eseguire comandi su ogni risultato.

Sintassi essenziale

find [PERCORSI...] [OPZIONI] [TEST ...] [AZIONI]
  • PERCORSI: uno o più punti di partenza (default: .).
  • TEST: condizioni di filtro (es. -name, -type, -size).
  • AZIONI: cosa fare con i risultati (es. -print, -exec, -delete).

Esempi veloci

Tutti i file .log nella cartella corrente (ricorsivo):

find . -type f -name "*.log"

Case-insensitive:

find . -type f -iname "*.jpg"

Solo nella cartella corrente, senza scendere nelle sottodirectory:

find . -maxdepth 1 -type f -name "*.sh"

Filtri comuni

Per nome e percorso

find /var/log -type f -name "syslog*"
find ~ -type f -path "*/node_modules/*"       # abbina al percorso completo
find . -regex '.*\.\(jpg\|png\|gif\)$'        # regex stile Emacs

Per tipo

find /etc -type f   # file regolari
find /etc -type d   # directory
find / -type l      # symlink
find . -type s      # socket
find . -type p      # pipe nominate

Per dimensione

-size accetta unità: c=byte, k=KiB, M=MiB, G=GiB. Prefissi: - “meno di”, + “più di”.

find . -type f -size +100M       # >100 MiB
find . -type f -size -10k        # <10 KiB
find . -type f -size 0           # esattamente 0 byte

Per tempo

-mtime giorni, -mmin minuti (ultimo modifica); analoghi: -atime/-amin (accesso), -ctime/-cmin (metadata).

find . -type f -mtime -1         # modificati nelle ultime 24h
find . -type f -mmin -30         # modificati negli ultimi 30 minuti
find /var/log -type f -mtime +7  # più vecchi di 7 giorni

Permessi, proprietari, vuoti

find . -empty                 # file o dir vuote
find . -user alice            # proprietario
find . -group www-data        # gruppo
find . -perm 0644             # permessi esatti (ottale)
find . -perm -0100            # contiene il bit eseguibile per il proprietario

Combinare condizioni

Operatori logici: -a/-and (AND), -o/-or (OR), ! (NOT). Usa parentesi per la precedenza; escapale in shell.

find . \( -name "*.png" -o -name "*.jpg" \) -type f ! -size 0

Escludere percorsi (pruning)

-prune evita di scendere in certe directory. Pattern tipico per saltare node_modules e .git:

find . -type d \( -name node_modules -o -name .git \) -prune -o -type f -print

Seguire symlink

find -L /path -type f -name "*.conf"   # -L segue i link simbolici

Stampare risultati

-print è implicito, ma puoi personalizzare con -printf (GNU find):

find . -type f -printf '%p %s bytes %TY-%Tm-%Td %TH:%TM\n'

Eseguire comandi sui risultati

-exec con \; vs +

  • -exec ... \; esegue il comando una volta per ogni file.
  • -exec ... + raggruppa più file in un’unica esecuzione (efficiente).
# Rimuovi estensioni .tmp (una invocazione per file)
find . -type f -name "*.tmp" -exec rm -v {} \;

# Comprimi in lotti (meno invocazioni)

find . -type f -name "\*.log" -mtime +7 -exec gzip -9 {} +

-ok: conferma interattiva

find . -type f -name "*.bak" -ok rm {} \;

-print0 e xargs -0 (spazi sicuri)

Usa terminatori NUL per gestire nomi con spazi o newline.

find . -type f -name "*.txt" -print0 | xargs -0 wc -l

Eliminare in modo sicuro

  • Prova prima con -print per verificare i match.
  • Preferisci -delete a -exec rm quando possibile; spesso è più sicuro e veloce.
# DRY RUN
find . -type f -name "*.tmp" -print

# Esegui davvero

find . -type f -name "\*.tmp" -delete

Per evitare di cancellare directory non vuote in modo imprevisto, alcune versioni richiedono -depth quando combini -delete con pattern su directory:

find . -depth -type d -name "__pycache__" -delete

Ricette pratiche

File più grandi di 1 GiB e mostrare dimensione “umana”:

find . -type f -size +1G -print0 | xargs -0 du -h

Cercare script eseguibili con shebang:

find . -type f -perm -0100 -exec head -n1 {} \; | grep -n "^#!"

Trova file modificati oggi e aprili in editor:

find . -type f -daystart -mtime 0 -exec "$EDITOR" {} +

Escludere cartelle di build e cercare sorgenti C/C++:

find . -type d \( -name build -o -name dist \) -prune -o \
  -type f \( -name "*.c" -o -name "*.cpp" -o -name "*.h" \) -print

Trova link simbolici rotti:

find . -xtype l

Ripulire file temporanei lasciati da editor:

find . -type f \( -name "*~" -o -name ".*.swp" -o -name ".DS_Store" \) -delete

Ordine, profondità e prestazioni

  • -maxdepth N limita l’esplorazione; -mindepth N salta i primi livelli.
  • -mount/-xdev evita di attraversare altri filesystem (utile su /).
  • -samefile, -inum e -links aiutano con hard link e inode.
# Cerca solo nel filesystem corrente
find / -xdev -type f -size +1G -print

Formattazione avanzata con -printf (GNU)

Specifica i campi come in printf(3):

  • %p=percorso, %f=nome, %h=dir, %s=byte
  • %u=utente, %g=gruppo, %m=permessi, %TY/%Tm/%Td=data
find . -type f -printf '%m %u %g %s %p\n' | sort -k4,4n

Pitfall comuni

  • Shell glob vs find: quotare i pattern ("*.txt") per evitare l’espansione della shell.
  • Spazi nei nomi: usa -print0 con xargs -0 o -exec ... {} +.
  • Parentesi: ricorda il backslash: \( ... \).
  • Compatibilità: opzioni come -printf sono GNU; su macOS potresti dover installare findutils (es. gfind).

Cheat sheet minimo

# Nomi
find . -name "*.ext"                # sensibile al case
find . -iname "*.ext"               # case-insensitive

# Tipo

find . -type f|d|l

# Dimensione

find . -size +100M                  # >100 MiB

# Tempo

find . -mtime -1                    # modificati < 1 giorno

# Profondità

find . -maxdepth 2 -mindepth 1

# Esclusioni

find . -path "*/.git/*" -prune -o -print

# Azioni

find . -exec cmd {} ;              # per-file
find . -exec cmd {} +               # batch
find . -delete                      # elimina (attenzione!)

# Sicurezza nomi

find . -print0 | xargs -0 cmd

Conclusione

find offre una grammatica ricca per interrogare il filesystem e automatizzare flussi di lavoro. Parti da pattern semplici, verifica con -print, poi aggiungi -exec o -delete con cautela. Con poche opzioni ben scelte, puoi sostituire script complessi e risparmiare tempo ogni giorno.

Torna su