5.2. find: cerca file in base a determinati criteri

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]
Se non specificate alcuna directory, find cercherà nella directory attuale. Se non specificate il criterio di ricerca, questo sarà considerato equivalente a "true", e quindi saranno trovati come corrispondenti tutti i file. Le opzioni, i criteri e le azioni sono così tanti che qui ne citeremo solo alcuni. Iniziamo con le opzioni:

Un criterio può essere costituito da uno o più controlli atomici fra i molti disponibili; alcuni controlli utili sono:

Esistono molti altri tipi di controlli, fate riferimento alla pagina di manuale relativa per ulteriori dettagli. Per combinare i controlli potete scegliere fra:

Infine, potete specificare una azione per ciascun file trovato. Le più frequentemente usate sono le seguenti:

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
Supponiamo che abbiate un server HTTP, e che tutti i vostri file HTML siano in /var/www/html, che è anche la vostra directory attuale. Volete cercare tutti i file il cui contenuto non è stato modificato da un mese a questa parte. Poiché possedete pagine create da diversi autori, alcuni file hanno l'estensione html mentre altri hanno l'estensione htm. Volete creare dei collegamenti a questi file nella directory /var/www/vecchi. Dovrete quindi scrivere[1]:
find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 -exec ln {} \
 /var/www/vecchi \;
Va bene, questo esempio è un po' complicato ed è necessaria una breve spiegazione. Il criterio è questo:
\( -name "*.htm" -o -name "*.html" \) -a -ctime -30
e fa quello che noi vogliamo: cerca tutti i file i cui nomi finiscono in .htm o .html "\( -name "*.htm" -o -name "*.html" \)", e che (-a) non sono stati modificati negli ultimi 30 giorni, che equivalgono più o meno a un mese (-ctime -30). Fate attenzione alle parentesi: in questo caso sono necessarie, perché -a ha una precedenza maggiore; se non le avessimo usate, sarebbero stati trovati tutti i file il cui nome finisce per .htm, più tutti i file il cui nome finisce per .html e che non sono stati modificati nell'ultimo mese, e questo non è quello che avevamo in mente. Notate anche che le parentesi sono disattivate dalla shell: se noi avessimo scritto ( .. ) invece di \( .. \), la shell le avrebbe interpretate e avrebbe cercato di eseguire -name "*.htm" -o -name "*.html" in una sotto-shell... Un'altra soluzione poteva essere quella di racchiudere le parentesi fra virgolette doppie o singole, ma una barra inversa (\) qui è preferibile perché dobbiamo isolare un solo carattere.

E, per finire, abbiamo il comando che deve essere eseguito su ogni file:
-exec ln {} /var/www/vecchi \;
Anche qui è necessario disattivare il ";" dalla shell, altrimenti questa lo interpreterebbe come un separatore di comandi. Se non lo fate, find lamenterà la mancanza di un argomento dell'opzione -exec.

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 è darth:
find /shared/images -cnewer     \
     /shared/images/stamp       \
     -a -iregex ".*\.jpe?g"     \
     -a -not -regex ".*/old/.*" \
       | mail darth -s "Nuove immagini"
Ed ecco fatto! Naturalmente questo comando non è molto utile se dovete riscriverlo per intero ogni volta, e inoltre potreste volere che sia eseguito periodicamente in automatico... Per fare ciò, leggete il prossimo paragrafo.

Note

[1]

Notate che per questo esempio è necessario che /var/www e /var/www/vecchi siano sullo stesso filesystem!


Tux on Star from MandrakeSoft Linux è un marchio registrato di Linus Torvalds. Tutti gli altri marchi e copyright appartengono ai rispettivi proprietari.
Se non diversamente specificato, i diritti di tutto il contenuto di queste pagine e di tutte le immagini sono proprietà di MandrakeSoft S.A. e MandrakeSoft Inc. 2000.
http://www.linux-mandrake.com/