LinuxPedia

Wiki libre et indépendant dédié à GNU-Linux et BSD.

Outils pour utilisateurs

Outils du site


commande:find

— page corrigée — oh!rocks 2009/05/09 20:48

"find" : outil de recherche et bien plus

“find” est avant tout un outil de recherche très complet, souple et disposant d'un grand nombre d'options. “find” peut également enchaîner des actions sur le résultat des recherches et utiliser des expressions régulières comme motifs de recherche, mais tout cela au prix d'une grande complexité d'utilisation. Il est courant de lire que “find” est un “bloatware” (“inflagiciel” ou “obésiciel” en Français) qui croule sous les options et peut consommer beaucoup de ressources.
Si la commande “find” est inconnue sur votre système, vous devrez installer un paquet qui la fourni, par exemple pour Debian ou Ubuntu le paquet “findutils”.
Essayons de donner des exemples pratiques d'utilisations courantes.

Un signe $ précède les commandes qui ne nécessitent pas de droits administrateur ; un signe # précède celles qui nécessitent des droits administrateur (ces signes ne font PAS partie des commandes). Les lignes qui ne commencent pas par un signe $ ou # correspondent au résultat de la commande précédente.
Les touches utilisées sont indiquées entre crochets, exemple [ctrl] pour la touche “contrôle”

Trouver un fichier

Trouver un élément d'après son nom

C'est l'usage le plus simple de “find” :

$ find /home/tux -name "[Vv]acances_été_2008"

Ici, nous cherchons dans /home/tux un fichier ou un répertoire dont le nom (option “-name”) est “vacances_été_2008”, avec ou sans majuscule (motif [Vv]).
Nous aurions pu également utiliser l'option “-iname” au lieu de “-name” : en effet, “-iname” fait abstraction de la casse (comme “grep -i” si vous connaissez la commande “grep”… sinon, c'est par là !).

La seule difficulté dans ce type d'usage est de construire le motif de recherche de façon pertinente. Surtout si vous ne savez pas exactement comment se nomme l'élément recherché… Voici un petit mémo des expressions qui peuvent vous servir à construire des motifs de recherche et que nous utiliserons par la suite :

expression correspond à
[aA] Lettre “a” en minuscule ou majuscule (ensemble de caractères possibles)
[1-9][aA-zZ] Tous les chiffres de “1” à “9”, ou toutes les lettres de l'alphabet, en majuscule ou minuscule
* joker, correspond à n'importe quel(s) caractère(s)
? joker, correspond à un seul caractère, peut être répété plusieurs fois
! Négation, avant un motif ou une option, signifie “n'est pas” ou “ne contient pas”

Il est préférable d'encadrer le nom à chercher par des guillemets doubles ou simples ' ; c'est d'ailleurs indispensable si ce nom contient des caractères spéciaux (*, ?, !…).
Si vous voulez trouver une image dont vous ne savez pas si elle est enregistrée en .jpg ou .png, et si le nom comporte des majuscules, il suffit de chercher :

$ find /home/tux/ -iname "vacances_25.??g"

Par défaut, “find” est récursif. La commande cherchera à partir de /home/tux dans tous les sous-répertoires. Cette récursivité peut s'avérer gênante si votre motif de recherche est très générique car les résultats se compteront par centaines ! Pour éviter cela on peut indiquer un niveau de profondeur maximum dans les sous-répertoires avec l'option -maxdepth :

$ find ~ -maxdepth 3 -name [Gg]nome*

Trouver les fichiers encombrants ou inutilisés...

Si votre disque dur se remplit dangereusement, vous pouvez utiliser “find” pour lister les fichiers les plus encombrants :

  • Ici nous cherchons tous les éléments dans le répertoire personnel de “tux” qui ont une taille (-size) supérieure (+600M) ou (-o pour “ou”) égale (600M) à 600 mégaoctets et dont le nom (-name) ne contient pas (!) l'extension .iso (on élimine les images de cd/dvd).
$ find /home/tux \( -size +600M -o -size 600M \) ! -name *.iso

find: `/home/lost+found': Permission non accordée
/home/tux/public/wine.tar.bz2
/home/tux/Video/big_buck_bunny_1080p_h264.mov
/home/tux/.VirtualBox/Machines/UBdesktop/Snapshots/{e9197acb-8cde-4ee6-b418-43a93174c1d8}.vdi
/home/tux/.VirtualBox/VDI/UBRAID2.vdi
/home/tux/.VirtualBox/VDI/UBRAID1.vdi
/home/tux/UBsrv.vmdk
find: `/home/.Trash-0': Permission non accordée

:!: Il est important de noter les “backslashes” (\) pour échapper (protéger de l'interprétation du shell) les parenthèses qui encadrent l'expression régulière, l'espace entre les parenthèses et l'expression elle même. La construction d'expressions régulières et la nécessité d'échapper les caractères spéciaux rendent le maniement de “find” assez complexe mais c'est le prix à payer pour ses usages quasiment illimités.

À noter également dans le résultat de la commande précédente, la présence de messages d'erreur “Permission non accordée”. C'est une simple question de droits sur les répertoires : pour être autorisé à chercher à l'intérieur de certains répertoires vous devez exécuter “find” avec des droits “root” (avec su ou sudo). Pour que ces erreurs ne polluent plus les résultats, lorsqu'il n'est pas nécessaire d'utiliser les droits “root” (recherche dans le répertoire personnel), il suffit de rediriger les messages d'erreur vers le “trou noir” /dev/null :

$ find /home/ \( -size +600M -o -size 600M \) ! -name *.iso -print 2> /dev/null

La taille des fichiers peut-être indiquée en gigaoctets (G), mégaoctets (M), kilooctets (k) ou octets (c).

  • Pour chercher les exécutables qui n'ont pas été utilisés au cours des 50 derniers jours sur les chemins /usr/bin, /bin et /opt:
$ find /usr/bin /bin /opt -executable  -atime +50
  • Toujours pour faire la chasse aux mégaoctets superflus, on recherche dans /var les éléments avec l'extension ”.log“ ou ”.deb“ (pour les systèmes basés sur les paquets .deb, type Debian ou Ubuntu), et qui ont une taille supérieure à 2 mégaoctets :
# find /var \( -name *.deb -o -name *.log -a -size +2M \)

Vous noterez l'usage des opérateurs logiques “-o” (un “ou” inclusif) et “-a” (pour “and”, “et” en français).

  • Chercher dans /tmp et /var/tmp les éléments qui n'ont pas été utilsés depuis 2 heures (120 minutes) :
# find /tmp /var/tmp -amin 120
  • Exclure un répertoire de la recherche. Pour cela on utilise l'option “-prune” dont la syntaxe n'est pas évidente. Ici nous cherchons dans le répertoire personnel de tux (~) les éléments de plus de 100 mégaoctets mais en excluant le sous-répertoire /home/tux/iso :
$ find ~ -path /home/tux/iso -prune -o size +100M

La syntaxe est donc “find chemin(s)_à_inclure -path chemin_à_exclure -prune -o options”.

  • Chercher dans l'ensemble du répertoire personnel mais sans descendre sur des volumes externes (option “-xdev”), tous les fichiers de plus de 100 mégaoctets et les lister par ordre décroissant (du plus gros au plus petit) :
$ find /home/tux -xdev -size +100M -print0 | xargs -0 ls -lS

Vous constatez que nous utilisons une seconde commande à la suite de “find” pour parvenir au résultat escompté.
Ce qui nous amène à la partie suivante…

Exécuter une commande sur le résultat de la recherche

:!: “find” peut exécuter une commande dans la foulée de la recherche. Cependant, il convient d'être très prudent avec cette fonction si on n'est pas certain de la pertinence du motif de recherche. Il est facile de commettre une erreur et de lister des éléments non désirés. Mieux vaut dans ce cas éviter de les envoyer à une commande “rm” (destruction)… Testez votre recherche “à blanc” avant d'effectuer une commande destructive.
Une possibilité est de remplacer “-exec” par “-ok”, ”-ok“ a la même fonction que ”-exec“ mais demande une confirmation pour chaque action (tapez [Y] ou [y] et validez pour accepter, validez directement pour refuser l'action). Comme une confirmation est demandée pour chaque résultat trouvé, l'option ”-ok“ n'est utilisable que pour un petit nombre d'actions (si vous avez 300 fichiers à supprimer, vous devrez taper 300 fois [y][entrée], soit 600 frappes…).

Pour passer le résultat d'une recherche “find” à une autre commande il existe deux moyens. L'un est propre à “find” et passe par l'option “-exec”, l'autre est plus générique et utilise “xargs”. “xargs” est en général plus efficace dans sa façon d'exécuter des traitements lourds.

  • Nous allons chercher les fichiers ”.ogg“ dans un répertoire ”~/Music“, et les copier dans un répertoire ”~/baladeur“ :
$ find ~/Music -name *.ogg -exec cp "{}" ~/baladeur \;

Petit décodage de la partie suivant l'ordre d'exécution ”-exec“ :

  1. on indique la commande à effectuer (ici “cp” pour “copier”) ;
  2. on indique que l'on souhaite exécuter “cp” sur le résultat de “find” : ce résultat est symbolisé par deux accolades {} ;
  3. pour éviter que ces accolades soient interprétées par le shell, on les encadre par des guillemets doubles ou simples ”{}“ ;
  4. on indique le chemin de destination (ici ~/baladeur) ;
  5. enfin, on termine la commande avec un point virgule ; que l'on protège par un backslash, comme ceci \; (on aurait pu également utiliser des guillemets simples, comme ceci ';').
  • Cette fois nous allons chercher les fichiers .mp3 dans le répertoire ”/Music/Salif Keita“ et les convertir en .ogg dans le répertoire courant à l'aide du script “mp32ogg” (à installer si besoin, avec votre gestionnaire de paquets) :
$ find '~/Muzic/Salif Keita' -name *.mp3 -exec mp32ogg "{}" \;

Rien de compliqué. Notons simplement que nous avons encadré le chemin de recherche avec des guillemets simples car il comportait un espace. Nous aurions pu également écrire :

$ find ~/Muzic/Salif\ Keita -name *.mp3 -exec mp32ogg "{}" \;

en protégeant l'espace avec un “antislash”.
Comme vous l'avez sans doute déjà remarqué, les espaces dans les noms de fichiers posent problème en ligne de commande. Cela va devenir encore plus important avec “xargs”…

  • Écrivons la même commande avec “xargs” au lieu de ”-exec“. Cela va nous amener à faire un peu de gymnastique car “xargs” ne supporte pas les espaces dans les noms de fichiers… Heureusement, la parade existe. Par défaut, “find” renvoie le résultat grâce à l'option implicite “-print” mais il peut également traiter le résultat en protégeant les espaces grâce à “-print0” (il s'agit d'un zéro, pas de la lettre “O”). Le résultat de “print0” peut alors être utilisé par “xargs” grâce à l'option “-0” (encore un zéro) qui attribue une valeur nulle aux espaces.

La commande devient :

$ find '~/Muzic/Salif Keita' -name *.mp3 -print0 | xargs -0 mp32ogg

Pourquoi utiliser “xargs” s'il est aussi pointilleux ?
La différence principale avec l'option ”-exec“ de “find” est le mode de traitement des données. “xargs” passe les données en une seule fois à la commande suivante alors que ”-exec“ appelle la commande suivante pour chaque résultat, conduisant à un certain gâchis de ressources. En bref, il n'y aura aucune différence sur des petits travaux mais si vous traitez un volume de données énorme un simple “ls -l” mettra votre machine à genoux avec ”-exec“ et passera beaucoup mieux avec “xargs”.

  • Compresser le résultat de la recherche. C'est un usage intéressant pour faire des sauvegardes ou reproduire une arborescence sur plusieurs machines. Ici on couple la recherche des fichiers d'extension *.flac à l'exécution de “tar” pour l'archivage :
$ find /home/tux/Music -name *.flac -print0 | xargs -0 tar -cvf flac.tar

Dans l'archive “tar” ainsi créée, toute l'arborescence des sous-répertoires contenant des résultats est préservée ; ce qui en rend la restauration très facile.

"find" comme auxiliaire de sécurité

Voyons quelques exemples dans lesquels “find” peut s'avérer un précieux auxiliaire de sécurité.

  • Créer une somme de contrôle md5 pour tous les fichiers dans /etc et écrire le résultat dans un fichier texte :
# find /etc -type f -exec md5sum "{}" > md5sum_etc_22042009.txt \;

On utilise l'option “-type f” pour sélectionner uniquement les fichiers. On peut arriver au même résultat avec “xargs” à un bémol près : pour les utilisateurs de “sudo” (Ubuntu et dérivées…), les droits “root” sont nécessaires pour effectuer une somme de contrôle sur certains fichiers de /etc or “sudo” ne persiste pas à travers les redirections de commande ; il faut donc écrire :

$ sudo find /etc -type f -print0 | sudo xargs -0 md5sum > md5sum_etc_22042009.txt
  • Rechercher, sur les chemins spécifiés, les éléments appartenant à “root” ( -user root ) et ( -a ) ayant les permissions ( -perm ) “suid” ( -u+s ) ou ( -o ) “sgid” ( -g+s ) puis exécuter la commande “ls -l” sur le résultat avant de passer ce dernier au pager “most” qui rend la lecture plus confortable (“most” n'est pas installé sur tous les systèmes : utilisez “less” ou “more” si vous ne souhaitez pas l'installer) :
$ find /sbin /bin /usr/bin /usr/sbin \( -user root -a -perm -u+s -o -perm -g+s \) -exec ls --color -l "{}" ';' |  most

On pourra ensuite réutiliser cette commande pour créer une liste de sommes de contrôle pour ces exécutables à surveiller de près (risques de sécurité par escalade de droits).

On peut imaginer un grand nombre d'applications de ce type. Vous trouverez dans le manuel (rubrique “TESTS”) de nombreuses options de recherche comme “-uid”, “-gid”, “-executable”, etc… qui vous aiderons à construire vos commandes.

Opérer sur du texte

“find” peut également être utilisé pour des recherches sur de multiples fichiers textes. On peut par exemple, créer un listing contenant les cinq premières phrases de chaque fichier texte correspondant aux critères de recherche :

$ find ~/Documents/Wiki \( -name '*.txt' -a -ctime -1 \) -exec head -n 5 -v "{}" \; > derniers_wiki.txt

Avec l'option ”-v“ de “head”, les noms des fichiers texte apparaitront dans le listing. ”-ctime -1“ correspond aux fichiers qui ont été modifiés dans les dernières 24 heures.

On peut également coupler “find” et “grep” :

$ find ~/Documents/Wiki \( -name '*.txt' -a -ctime +2 \) -exec grep -H "mdadm.conf" "{}" \;

L'option ”-H“ de “grep” permet d'avoir le nom du fichier en plus des lignes trouvées. ”-ctime +2“ correspond aux fichiers qui n'ont pas été modifiés dans les dernières 48 heures.

Nous n'avons fait qu'effleurer la surface des possibilités offertes par “find” ; à vous d'inventer les usages qui vont avec sa pléthore de fonctions.

commande/find.txt · Dernière modification : 2018/11/17 12:52 de 127.0.0.1