find è un veterano tra i comandi Unix. Il suo scopo è analizzare ricorsivamente una o più directory e cercare all'interno di esse i file che corrispondono a determinati criteri. Sebbene sia molto utile, la sua sintassi è veramente complessa, ed è necessario un certo impegno per utilizzarlo. La sintassi generale è:
find [opzioni] [directory] [criterio] [azione] |
-xdev: esclude dalla ricerca le directory che risiedono su altri filesystem.
-mindepth <n>: effettua la ricerca solo sui livelli a partire dal livello n al di sotto della directory specificata.
-maxdepth <n>: cerca i file che si trovano al massimo n livelli al di sotto della directory specificata.
-follow: segue i link simbolici corrispondenti a directory. Come comportamento predefinito, find non li segue.
-daystart: in caso di controlli relativi al tempo (vedi sotto), considera come orario l'inizio del giorno attuale invece del valore predefinito (24 ore prima dell'orario attuale).
Un criterio può essere costituito da uno o più controlli atomici fra i molti disponibili; alcuni controlli utili sono:
-type <tipo>: cerca un determinato tipo di file; <tipo> può essere uno dei seguenti: f (file normale), d (directory), l (collegamento simbolico), s (socket), b (file in modalità a blocchi), c (file in modalità a caratteri) o p (pipe con nome).
-name <modello>: cerca i file i cui nomi corrispondono al <modello> indicato. Con questa opzione, il <modello> è considerato come un modello di meta-espansione (si veda il capitolo I caratteri speciali (meta-caratteri) e le espressioni regolari nella shell).
-iname <modello>: come -name, ma non distingue tra maiuscole e minuscole.
-atime <n>, -amin <n>: cerca i file che sono stati letti <n> giorni fa (-atime) o <n> minuti fa (-amin). Potete anche usare +<n> o -<n>, e in questo caso saranno cercati i file letti rispettivamente al massimo o al minimo <n> giorni/minuti fa.
-anewer <file>: cerca i file che sono stati letti più recentemente del file <file>.
-ctime <n>, -cmin <n>, -cnewer <file>: sono equivalenti a -atime, -amin e -anewer, ma considerano la data dell'ultima modifica del file.
-regex <modello>: come -name, ma il modello viene considerato come una espressione regolare.
-iregex <modello>: come -regex, ma non distingue tra maiuscole e minuscole.
Esistono molti altri tipi di controlli, fate riferimento alla pagina di manuale relativa per ulteriori dettagli. Per combinare i controlli potete scegliere fra:
<c1> -a <c2>: è vero se sono veri sia <c1> che <c2>; -a è implicito, quindi potete scrivere <c1> <c2> <c3> ... se volete che siano verificati tutti i controlli <c1>, <c2>, ...
<c1> -o <c2>: è vero se almeno uno tra <c1> e <c2> è vero. Ricordate che -o ha una precedenza inferiore a -a, e quindi se volete, ad esempio, cercare i file che corrispondono ad almeno uno dei criteri <c1> e <c2> oltre che al criterio <c3>, dovrete usare le parentesi e scrivere ( <c1> -o <c2> ) -a <c3>. Dovrete usare una sequenza escape per le parentesi (disattivandole), perché altrimenti saranno interpretate dalla shell!
-not <c1>: inverte il controllo <c1>, pertanto -not <c1> è vero se <c1> è falso.
Infine, potete specificare una azione per ciascun file trovato. Le più frequentemente usate sono le seguenti:
-print: stampa il nome di ciascun file sullo standard output. Se non specificate alcuna azione, questo è il comportamento predefinito.
-ls: stampa sullo standard output l'equivalente del comando ls -ilds per ogni file trovato.
-exec <comando>: esegue il comando <comando> per ogni file trovato. La linea di comando <comando> deve terminare con un ";", per il quale deve essere utilizzata una sequenza escape in modo che la shell non lo interpreti; la posizione del file è rappresentata da {}. Per maggiori chiarimenti si vedano gli esempi di utilizzo.
-ok <comando>: come -exec, ma chiede conferma per ogni comando.
Ci siete ancora? Bene, ora facciamo un po' di pratica, è sempre il modo migliore per capire questo mostro. Supponiamo che vogliate trovare tutte le directory contenute in /usr/share. Dovrete scrivere:
find /usr/share -type d |
find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 -exec ln {} \ /var/www/vecchi \; |
\( -name "*.htm" -o -name "*.html" \) -a -ctime -30 |
E, per finire, abbiamo il comando che deve essere eseguito su ogni file:
-exec ln {} /var/www/vecchi \; |
Un ultimo esempio: supponiamo che abbiate una directory /shared/images enorme, contenente tutti i tipi di immagini possibili, e supponiamo che di solito voi usiate il comando touch per aggiornare la data di un file di nome stamp contenuto nella stessa directory, in modo da avere un riferimento temporale. Vogliamo cercare in questa directory tutte le immagini JPEG più recenti del file stamp, e poiché possedete immagini provenienti da diverse fonti, questi file potranno avere estensione jpg, jpeg, JPG o JPEG. Vogliamo anche evitare di cercare nella directory old. Vogliamo infine che questa lista di file ci venga spedita via e-mail, e il nostro nome utente è tuxor:
find /shared/images -cnewer \ /shared/images/stamp \ -a -iregex ".*\.jpe?g" \ -a -not -regex ".*/old/.*" \ | mail tuxor -s "Nuove immagini" |
[1] | Notate che per questo esempio è necessario che /var/www e /var/www/vecchi siano sullo stesso filesystem! |
Indietro | Partenza | Avanti |
Strumenti da linea di comando | Risali | crontab: analizzare o modificare il file crontab |