« find » : Quelques rappels

Parmi les commandes qui font la puissance de Linux, nous comptons la commande « find » destinée à effectuer des recherches en lignes de commande. Rares sont les jours ou elle n’est pas sollicitée sur un système… Ses possibilités sont telles que ça méritait bien une petite brève…

Ce post n’est pas une ré écriture des man et autres docs sur « find », il s’agit juste de quelques exemples rappelant l’usage de fonctionnalités plus ou moins fréquemment utilisées. N’hésitez pas à proposer vos exemples d’utilisation de « find »

Rappels

Les appels à « find » sont schématiquement et en simplifiant structurés comme suit :

find [où] [critères] [opérations]

  • [où] est le point de départ de la recherche ;
  • [critères] sont les critères de sélection des fichiers ;
  • [opérations] sont les opérations éventuelles à effectuer sur les résultats de la recherche.

Les critères de recherches peuvent être combinés de manières plus ou moins complexes en utilisant les opérateurs logiques « et » (« -and ») , « ou » (« -or ») et « non » (« -not ») et priorisés en utilisant les parenthèses.

Par exemple :

find /etc -type f \( -name "syslog*" ! -iname "*.conf" \)

recherche dans « /etc » les fichiers (« -type f ») commençant par « syslog » (‘-name « syslog* »‘) et ne finissant pas par « .conf » (‘! -iname « *.conf »‘). Le « i » de « iname » signifie « insensible à la case » (majuscule et minuscule).

Remarquez que dans ce cas les parenthèses ne sont pas d’un intérêt débordant…

Exclure des fichiers/des répertoires d’une recherche

Comme dans le rappel ci dessus, vous pouvez utiliser l’opérateur de négation « ! » pour exclure certain fichiers de vos recherches.

Par exemple pour rechercher les répertoires de « /etc » contenant la chaîne de caractère « conf », mais ne commençant pas par « conf » ET contenant « test » OU tous ceux contenant « test » en fin de ligne, nous pourrions écrire :

find /etc -type d -and \( \( ! -name "conf*" -and -name "*conf*" -and -name "*test*" \) -or -name "*test" \)

qui ce lit : rechercher dans « etc » des répertoires ET [ [ leurs noms ne commencent pas « conf » ET contiennent « conf » ET contiennent « test »] OU [ leurs noms finissent par « test » sans autres conditions]].

ATTENTION : Les répertoires ne correspondant pas à ces critères sont exclus du résultat, mais par leurs contenu ! Si un répertoire correspondant aux critères est contenu par un répertoire n’y correspondant pas, il sera trouvé !

Par exemple :

09:25:53 fhh@mafalda ~ $ tree test
test
??? rep1
?   ??? repertoire1
?   ??? repertoire2
??? rep2
    ??? repertoire1
    ??? repertoire2

6 directories, 0 files
09:25:57 fhh@mafalda ~ $ find test -type d ! -name "*1"
test
test/rep1/repertoire2
test/rep2
test/rep2/repertoire2

« find » trouve « test/rep1/repertoire2 » alors que « rep1 » est exclu du résultat de la recherche…

Pour exclure le contenu d’un répertoire d’une recherche, vous DEVEZ utiliser l’option « -prune » en complément de l’exclusion. Ainsi pour exclure les répertoires ce terminant par « 1 » et leur contenu de la recherche précédente, nous écririons :

find test -type d ! \( -name "*1" -prune \)

qui retourne à l’execution :

09:25:57 fhh@mafalda ~ $ find test -type d ! \( -name "*1" -prune \)
test
test/rep2
test/rep2/repertoire2

la recherche exclu les répertoires terminant par 1 et leur contenu du résultat.

Bien sûr l’exemple est donné en fonction du nom du répertoire ( critère « -name ») mais cela peut s’appliquer à tous les critères de recherche comme : « éviter de s’intéresser aux répertoires plus récents que X jours », etc.

Rechercher les fichiers appartenant à un utilisateur ou à un groupe

Les options « -user » et « -group » permettent respectivement de trouver les fichiers appartenant à un utilisateur ou à un groupe :

find /var -user mysql

retourne les fichiers de /var appartenant à l’utilisateur « mysql » et :

find /var -group mysql -iname "*.myi"

retourne les fichiers de « /var » appartenant au groupe « mysql » et terminant par « .MYI », « .myi », « .MyI », … (bref par « .myi » insensible à la case…).

Rechercher les fichiers non associés à un utilisateur ou à un groupe

Les options « -nouser » et « -nogroup » permettent d’effectuer une recherche sur les fichiers orphelins d’utilisateur ou de groupe, c’est à dire les fichiers appartenant à un utilisateur ou à un groupe n’existant pas sur le système.

find -nogroup -ls

Qui donne à l’exécution :

12:33:40 fhh@mafalda ~ $ find -nogroup -ls
   175  244 -rw-r--r--   1 fhh      1010       247844 Nov 12 01:48 ./20101111.ldap.ldif

visiblement ce fichier appartiens à « fhh » mais le groupe d’appartenance 1010 est inconnu… Le fait de ne pas préciser le chemin de recherche la lance dans le répertoire courant.

Rechercher les fichiers en fonction des droits appliqués

Les recherches sur les permissions commencent par les attributs « -readable », « -writable » et « -executable » permettant de rechercher les fichiers respectivement accessibles en lecture, écriture et en exécution.

L’option « -perm » effectue une recherche ciblée sur les droits appliqués à des fichiers et/ou des répertoires. Ainsi, la commande :

find /sbin -perm 2755

retourne tous les fichiers disposant EXACTEMENT des droits « *rwxr-sr-x ». Cette recherche peut être effectuée sans utiliser la notation octale :

find /sbin -perm g+s,a+rx,u+w

« – » Ou « + » permettent respectivement de rechercher les fichiers ayant AU MOINS ou CERTAINES des autorisations spécifiées.

Par exemple pour lister les fichiers de /usr AU MOINS exécutables par tous et ayant le « setuid » activé (droit d’exécution en endossant les droits du propriétaire du fichier), nous saisirions :

find /usr -perm -4111 -ls

notez le « -ls » permettant de lister en détail les fichiers trouvés.

Nous aurions simplement recherché les fichiers dont le « setuid » était activé via :

find /usr -perm +4000 -ls

Rechercher les fichiers en fonction de leur taille

C’est logiquement l’option « -size » qui permet de rechercher des fichiers en fonction de leur taille :

find ~ -size 100

recherche les fichiers d’exactement 100*512 byte dans le répertoire home de l’utilisateur.

Les opérateurs « + » ou « – » devant la taille spécifiée permettent respectivement de rechercher les fichiers de taille « supérieure à taille » ou « inférieure à taille ». Par exemple :

find ~ -size +10M

affiche les fichiers du répertoire de l’utilisateur d’une taille supérieure à 10 Megabytes tandis que :

find ~ -size -100k

n’affiche que les fichiers d’une taille inférieure à 100 kilobytes (100*1024 bytes).

Les unités spécifiées ont une valeur parmis (sortie directe du « man » de find) : b pour blocks (groupes de 512 byte) ; c pour bytes ; w pour « words » (2 bytes ou 2 c) ; k pour kilobytes (1024 bytes) ; M pour megabytes (1048576 bytes) ou G pour gigabytes (1073741824 bytes).

Notons que l’option « -empty » permet d’effectuer une recherche des fichiers vides.

Rechercher des fichiers en fonction de leurs date de modification/d’accès/de création

Les options « -atime », « -ctime » et « -mtime » permettent de rechercher les fichiers ayant été respectivement accédés, créés ou modifiés depuis moins de (« -« ), exactement ou plus de (« + ») N jours. Remplacer « time » par « min » pour utiliser les minutes comme base de temps au lieu des jours.

find /etc -mtime -1

Donne la liste des fichiers de « /etc » ayant été modifiés ces dernières 24 heures.

find /tmp -atime +5 -exec rm -ri {} \;

Supprime (après confirmation) tous les fichiers (et répertoires mais sous unix tout est fichiers alors…) de « /tmp » n’ayant pas été utilisés depuis plus de 5 jours (voir plus bas : « Appliquer un traitement aux résultat d’une recherche »).

Rechercher les fichiers plus récents qu’un autre

« -newer » Permet de rechercher les fichiers plus récents qu’un autre :

find ~ -newer ~/test

affiche les fichiers du répertoire de l’utilisateur plus récents que le fichier « test » du même répertoire.

La page de man vous présentera les variantes permettant de s’intéresser aux dates de création, de modification et/ou d’accès.

Pour créer une archive des fichiers de « ~/web » modifiés depuis la dernière archive effectué, nous pourrions écrire :

find ~/web -newer ~/sauvegarde.tar.bz2 -exec tar uvf ~/modifie_depuis_sauvegarde.tar {} \;

Rechercher les liens symboliques pointant vers un fichier

Pour trouver les liens symboliques pointant vers un fichier, vous pouvez utiliser l’option « -lname » (pour « link name » sans doute 😉 ) ou « -ilname » (le même insensible à la case). Ainsi trouver le ou les liens de « /usr/lib » pointant vers « libstdc++.so.6.0.13 », vous pourriez écrire :

find /usr/lib -lname libstdc++*

Appliquer un traitement aux résultat d’une recherche

Vous pouvez appliquer à la volée un traitement sur le résultat d’une recherche via l’option « -exec ».

Par exemple, pour archiver tous les répertoires RCS de votre répertoire « /etc » nous ferons :

find /etc/ -type d -name RCS -exec tar uvf ~/archives_rcs.tar {} \;

ou pour supprimer tous les fichiers ou dossiers du répertoire « ~/tmp » âgés de plus de 3 jours :

find /home/fhh/Téléchargements/ -mtime +3 -exec rm -rf {} \;

Vous pouvez enregistrer le résultat détaillé d’une recherche directement dans un fichier via l’option « -fls nom_fichier« .

Enfin il est possible de définir la manière d’afficher le résultat d’une recherche via l’option « -printf format« . Je vous laisse consulter la page de man de find pour plus de renseignements sur la définition des formats.

Limiter l’étendue d’une recherche

Il existe différentes options permettant de contrôler le mode de parcours de find. Le man vous les détaillera très bien, notons simplement les options « -mindepth N » et « -maxdepth X » permettent de commencer la recherche au niveau « N » et de ne pas la poursuivre au delà du niveau « X ». Par exemple, pour rechercher tous les homedirs du répertoire home, nous pourrions faire :

find /home -mindepth 1 -maxdepth 1 -type d

Notez la position des options mindepth et maxdepth (avant les critères de recherche eux même…).

L’option « -xdev » quand à elle assure que la recherche ne sortira pas du système de fichier à la base de la recherche.

Utilisez les expressions régulières dans vos recherches

Pour utiliser les expressions régulières dans les recherches, nous devrons définir 2 options distinctes :

  • -regextype qui définit la syntaxe qui sera utilisée dans l’expression régulière, ses valeurs peuvent être « posix-awk » pour utiliser la syntaxe « awk », « posix-egrep » pour la syntaxe « egrep », etc ;

  • -regex qui définit l’expression régulière elle même…

Par exemple, la recherche des fichiers aux extensions « jpg », « jpeg » et « png » du répertoire « ~/public_html » peut s’écrire :

find ~/public_html/ -regextype posix-egrep -regex  '.*\.(jpe?g|png)$'

Références

Man find : http://pwet.fr/man/linux/commandes/find

4 réflexions au sujet de « « find » : Quelques rappels »

  1. Mais alors, quelle est la différence entre l’option -exec de find, et l’utilisation de xargs ? Le but semble identique, non ?

    Merci pour l’article, très bon pense bête (c’est moi la bestiole ;))

    1. La différence réside dans le mode de traitement des arguments. « exec » va appliquer un traitement fichier par fichier là ou le passage par xargs va appliquer le traitement à la liste résultante de la commande. Exemple :

      fhh@melusine ~ $ find ex -type f -exec echo {} \;
      ex/c
      ex/b
      ex/a
      fhh@melusine ~ $ find ex -type f | xargs echo
      ex/c ex/b ex/a
      
  2. Exemple d’utilisation simple de find mais couplée à d’autres commandes.
    1) Renomme tous les fichiers MaLib*.cpp et MaLib*.h en UneLib* :
    find . -name « *.cpp » -or -name « *.h » | xargs rename « s/MaLib/UneLib/g »
    2) Remplace la chaîne MaLib dans les sources par UneLib (pour remplacer un namespace de partout, par exemple) :
    find . -name « *.cpp » -or -name « *.h » | xargs sed -i « s/MaLib/UneLib/g »

    Très utile pour recycler son code !
    (j’ai bien dit « son propre code, hein ;oP)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *