5.2. find : rechercher des fichiers selon certains critères

find est un utilitaire Unix depuis longtemps. Son but est de parcourir récursivement un ou plusieurs répertoires et d'y trouver des fichiers correspondant à un certain ensemble de critères. Bien qu'il soit très utile, sa syntaxe est vraiment complexe, et l'utiliser requiert une certaine habitude. La syntaxe générale est :
find [options] [répertoires] [critère] [action]
Si vous ne spécifiez aucun répertoire, find recherchera dans le répertoire courant. Car l'absence de critère, équivaut à « vrai  », et donc tous les fichiers seront trouvés. Les options, les critères et les actions possibles sont si nombreux que nous n'en mentionnerons que quelques-uns ici. Commençons par les options :

Un critère peut être un ou plusieurs tests atomiques; quelques tests utiles sont :

Beaucoup d'autres tests existent, référez-vous à la page de manuel pour plus de détails. Pour combiner ces tests, vous pouvez utiliser :

Enfin, vous pouvez demander une action précise pour chaque fichier retrouvé. Les plus fréquentes sont :

  1. -print : Écrit seulement le nom de chaque fichier sur la sortie standard. C'est l'action par défaut si vous n'en spécifiez aucune.

  2. -ls : Affiche l'équivalent d'un ls -ilds sur chaque fichier trouvé sur la sortie standard.

  3. -exec <commande> : Exécute la commande <commande> sur chaque fichier trouvé. La ligne de commande <command> doit se terminer par un ;, que vous devez désactiver de telle sorte que le shell ne l'interprète pas; la position du fichier est repérée par {}. Regardez les exemples d'utilisation pour bien comprendre.

  4. -ok <commande> : Même chose que -exec mais demander confirmation pour chaque commande.

Toujours là? Alors, maintenant entraînons-nous un peu, c'est après tout la meilleure façon de maîtriser ce monstre ! On supposera ceci : vous désirez trouver tous les répertoires dans /usr/share. Tapez alors : find /usr/share -type d Admettons que vous avez un serveur HTTP, que tous vos fichiers HTML sont dans /var/www/html, qui s'avère aussi être votre répertoire courant. Il s'agit de chercher tous les fichiers qui n'ont pas été modifiés depuis... un mois, par exemple. Les pages proviennent, incidemment, de différents auteurs : certains fichiers auront une extension html et d'autres, l'extension htm. Vous voulez lier ces fichiers dans le répertoire /var/www/obsolete. Vous taperez alors[1] :
find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 \
-exec ln {} /var/www/obsolete \;
D'accord, cette exemple est un peu compliqué et requiert quelques explications. Le critère est :
\( -name "*.htm" -o -name "*.html" \) -a -ctime -30
qui accomplit ce qu'on lui demande : il recherche tous les fichiers dont le nom se termine soit par .htm, soit par .html (\( -name "*.htm" -o -name "*.html" \)), et (-a) qui n'ont pas été modifiés dans les derniers 30 derniers jours, ce qui représente en gros un mois (-ctime -30). Notez les parenthèses : elles sont nécessaires ici, parce que -a a une priorité plus grande. En leur absence, tous les fichiers se terminant par .htm auraient été sortis, plus tous les fichiers se terminant par .html n'ayant pas été modifiés depuis un mois, ce qui n'est pas ce que nous voulons. Notez également que les parenthèses sont désactivées par rapport au shell : si nous avions mis ( .. ) à la place de \( .. \), le shell les aurait interprétés et aurait tenté d'exécuter -name "*.htm" -o -name "*.html" dans un sous-shell... Une autre solution aurait été de mettre les parenthèses entre doubles ou simples apostrophes, mais une anti-barre oblique (backslash) est préférable ici dans la mesure où nous ne devons isoler qu'un seul caractère.

Et enfin, la commande doit être exécutée pour chacun des fichiers :
-exec ln {} /home/httpd/obsolete \;
Ici aussi, vous devez désactiver le ; par rapport au shell, car autrement le shell l'interprétera comme un séparateur de commandes. Si vous ne le faites pas, find se plaindra qu'il manque un argument à -exec.

Un dernier exemple : vous avez un gros répertoire nommé /shared/images, contenant toutes sortes d'images. Régulièrement, vous utilisez la commande touch pour mettre à jour les dates d'un fichier nommé stamp dans ce répertoire, de façon à avoir une référence dans le temps. Vous voulez trouver tous les fichiers JPEG dans ce répertoire qui sont plus récents que le fichier stamp, et comme vous avez des images de diverses sources, ces fichiers ont des extensions jpg, jpeg, JPG ou JPEG. Vous voulez aussi éviter de rechercher dans le répertoire old. Vous voulez vous faire envoyer la liste de ces fichiers par courrier électronique, et votre nom d'utilisateur est pierre :
find /shared/images -cnewer     \
     /shared/images/stamp       \
     -a -iregex ".*\.jpe?g"     \
     -a -not -regex ".*/old/.*" \
       | mail pierre -s "Nouvelles images"
Et voilà! Bien sûr, cette commande n'est pas très utile si vous devez l'exécuter régulièrement car vous devrez l'entrer à chaque fois. Il est possible de le faire ainsi :

Notes

[1]

Notez que cet exemple requiert que /var/www et /var/www/obsolete soient sur le même système de fichier!


Tux sur Étoile de MandrakeSoft Linux est une marque déposée de Linus Torvalds. Toutes les autres marques et copyrights sont la propriété de leurs auteurs respectifs.
Sauf mention contraire, tout le contenu de ces pages et toutes les images sont Copyright MandrakeSoft S.A. et MandrakeSoft Inc. 2001.
http://www.mandrakelinux.com/