Exploitez la puissance de la commande find

Les système Unix/Linux possèdent un grand nombre de commandes permettant d’effectuer les tâches d’administration de tous les jours… La commande find est une de celles-là. Elle sait faire bien plus que chercher des fichiers. La commande find permet de trouver tous les fichiers mp3, tous les fichiers d’un utilisateur donné, tous les fichiers exécutables, tous les fichiers modifiés à une date donnée, etc. En la combinant avec xargs, il est possible d’exécuter des tâches sur les fichiers trouvés avec un gain de temps assez conséquent. C’est ce que nous allons voir dans cet article.

Trouver des fichiers grâce à la commande find

Les bases

find où-chercher critères

Le premier argument doit être la liste des répertoires dans lesquels effectuer la recherche. Il est possible de rechercher dans plusieurs répertoires à la fois en fournissant plusieurs arguments. La commande find n’entrera pas dans un répertoire si vous n’avez pas les droits. Voici un premier exemple qui permettra de trouver tous les fichiers présents dans les dossiers /home/you et /home/me.

find /home/you /home/me

Recherche par nom

La recherche par nom se fait grâce à l’option -name. Cette option peut prendre un nom complet de fichier comme une simple expression contenant * (plusieurs caractères) et ? (un caractère). Il est par exemple possible, de trouver tous les fichiers ayant l’extension mp3 dans notre répertoire personnel.

find ~ -name "*.mp3"

Si certains de nos fichiers ont une extension en majuscule, la commande précédente ne les trouvera pas. Il est alors plus intéressant d’utiliser l’option -iname, qui elle, n’est pas sensible à la casse.

find ~ -iname "*.mp3"

Utiliser les guillemets dans le critère de recherche est une bonne habitude à prendre car cela permet d’éviter les problèmes avec les caractères génériques du Shell.

Recherche par utilisateur et groupe

Vous souhaitez trouver tous les fichiers d’un utilisateur particulier dans le dossier /tmp ? Rien de plus facile, il suffit pour cela d’utiliser l’option -user.

find /var/www -user me

On utilise l’option -group pour trouver les fichiers appartenant à un groupe donné.

find /var/www -group users

Recherche par type

Pour trouver un fichier, un dossier, un lien…, il suffit d’utiliser l’option -type. Voici un exemple permettant de trouver tous les répertoires de notre répertoire personnel.

find ~ -type d

Voici quelques unes des valeurs utilisables avec cette option :

  • répertoire : d ;
  • fichier : f ;
  • lien : l ;
  • socket : s ;
  • tube (pipe) : p.

Dans les exemples précédents, et dans les suivants certainement aussi, on parle de fichiers, c’est un abus de langage car sous Linux, tout est fichier. Donc lorsque l’on ne précise pas le -type à rechercher, la commande find recherchera des fichiers, des dossiers, des sockets, etc.

Lister les fichiers vides

C’est tout simple, grâce à l’option -empty.

find / -empty

Recherche par taille de fichier

On veut savoir quels sont les fichiers qui sont plus gros que 10 Mo ? Rien de plus simple, il suffit d’utiliser l’option -size.

# notez le +
find ~ -size +10M

Pour trouver ceux de moins de 10 ko :

# notez le -
find ~ -size -10k

Pour trouver ceux de 10ko exactement (voir note ci-dessous) :

# pas de + ou de -
find ~ -size 10k

Il est possible d’utiliser le suffixe M pour Méga Octets, G pour Giga Octets, c pour octets. Si vous recherchez les fichiers d’exactement 5k, le résultat comprendra les fichiers compris entre 4 ko et 5 ko. Il est possible de chercher un fichier faisant entre 1 Mo et 2 Mo en combinant les options. Cette notion est abordée dans la partie suivante.

Combiner les options

Les options vues précédemment sont pratiques, mais le seraient encore plus s’il était possible de les combiner. C’est bien sûr possible. Les combinaisons peuvent se faire selon les trois opérateurs suivants : ET, OU et NON. Par défaut, les options sont combinées en tant que ET -a. Si vous souhaitez utiliser l’opérateur OU, il suffit d’utiliser l’option -o, et si vous souhaitez utiliser la négation, il suffit d’utiliser l’option !.

Ici, on recherche les fichiers qui ont l’extension mp3 et qui appartiennent à l’utilisateur me.

find /home -type f -a -name "*.mp3" -a -user me
# les options sont combinées par défaut en ET, donc pas la peine de les spécifier dans ce cas
find /home -type f -name "*.mp3" -user me

La même, mais en excluant les fichiers qui ont une taille supérieure à 3 Mo :

find /home -type f -name "*.mp3" -user me \! -size +3M

Pour modifier la priorité des opérateurs, on pourra utiliser les parenthèses. Comme les parenthèses ont une signification particulière dans le Shell, il faut les échapper. L’exemple suivant permet de rechercher les fichiers .jpg ou .png appartenant à l’utilisateur me.

find . -user me -a \( -iname ".jpg" -o -iname ".png" \)

Options avancées

La commande find possède aussi un nombre d’options qui permettent de répondre à certaines questions telles que : “Quels sont les fichiers qui ont été modifiés dernièrement ?” ou “Quels sont les fichiers dont les permissions ont été changées récemment ?”…

Recherche par date de dernière modification du contenu

Cette recherche s’effectue grâce à l’option -mtime. Elle prend en paramètre un entier, un nombre de jours (période de 24 heures). Pour trouver tous les fichiers dans /etc appartenant à root et dont le contenu a été modifié il y a moins de deux jours, il suffit de faire ceci :

# notez le -2
find /etc -mtime -2 -user root

Pour trouver ceux qui ont été modifiés il y a plus de 5 jours :

# notez le +5
find /etc -mtime +5 -user root

Et ceux qui ont été modifiés il y a 10 jours exactement :

# pas de + ou de -
find /etc -mtime 10 -user root

Options relatives aux dates

Les options suivantes sont similaires à l’option vue précédemment.

  • -atime permet de trouver un fichier par date de dernier accès ;
  • -ctime permet de trouver un fichier par date de dernière modification des permissions ou de changement de propriétaire.

Il existe également la version minute des options précédentes : -mmin, -amin, -cmin.

Voici un exemple permettant de trouver les fichiers dans /var/www pour lesquels il y a eu un accès dans les 2 dernières minutes.

find /var/www -amin -2

Recherche par permissions

L’option -perm permet de trouver des fichiers en fonction de leurs permissions. Il est possible d’utiliser la notation octale pour spécifier la valeur des permissions, par exemple 0755, ou la notation littérale u=rwx,g=rw,o=rw.

Trois notations sont utilisables avec les permissions : sans préfixe, précédé du signe – ou précédé du signe /.

  • Sans préfixe : le mode du fichier doit être exactement celui passé à l’option -perm. Par exemple, si on cherche les fichiers ayant le mode u=rwx (0700), tous les fichiers que l’on trouvera auront exactement le mode u=rwx (0700).
  • – : le mode du fichier doit être au moins égal à celui passé à l’option -perm. Par exemple, si on cherche les fichiers ayant le mode -u=r (-0400), tous les fichiers que l’on trouvera auront alors les modes suivants : u=r ou u=rw ou u=rx ou u=rwx ou u=r,g=x… En d’autres termes, cela signifie que si l’on cherche tous les fichiers en lecture, on pourra trouver aussi ceux qui sont en lecture et écriture, ou encore en lecture et exécution…
  • / : un des modes (user, group ou other) doit être au moins égal à ceux passés à l’option -perm. Par exemple, si on cherche les fichiers ayant le mode /u=w,g=w,o=w, tous les fichiers que l’on trouvera auront alors les modes suivants : u=w ou g=w ou o=w ou u=w,g=w,o=w ou u=rw,g=rwx…

N’hésitez surtout pas à faire des essais pour bien comprendre le fonctionnement de cette option.

Pour trouver les fichiers qui sont exactement en lecture et écriture pour l’utilisateur, le groupe et les autres, il suffit de faire :

find . -perm 666

Pour trouver les fichiers qui sont exécutables par son propriétaire :

find . -perm -u=x

Pour trouver tous mes fichiers de mon répertoire personnel et qui sont en écriture pour le groupe ou pour les autres :

find ~ -type f -user me -perm /g=w,o=w
# ou mieux, avec une substitution de commande
find ~ -type f -user $(whoami) -perm /g=w,o=w

Identification des fichiers orphelins

Vous avez supprimé des utilisateurs ou groupes du système et vous avez oublié de supprimer les fichiers associés ? Vous pouvez retrouver ces fichiers grâce aux options -nouser et -nogroup.

# pour trouver les fichiers qui ne sont pas associés à un user id existant
find / -nouser
# pour trouver les fichiers qui ne sont pas associés à un group id existant
find / -nogroup

Effectuer des opérations sur les fichiers trouvés

Maintenant que vous savez rechercher des fichiers, vous allez pouvoir exécuter des commandes sur les fichiers trouvés. Bien que nde la commafind dispose de son propre mécanisme pour exécuter des commandes, nous utiliserons args car il est plus souple et plus rapide. Cette commande reçoit sur l’entrée standard (stdin), grâce à un pipe (tube), la liste des fichiers trouvés. Elle exécute ensuite la commande passée en argument sur la liste complète des fichiers reçus via stdin.

Ainsi, il est possible de supprimer tous les fichiers thumbs.db (fichiers système Windows) que l’on aurait copiés via samba dans notre répertoire personnel.

find ~ -type f -iname "thumbs.db" -print0 | xargs -0 -r rm -v

Une bonne pratique d’utilisation consiste à utiliser l’option -print0 et l’argument -0 pour éviter d’avoir des problèmes avec les espaces ou les caractères spéciaux dans les chemins. En effet, par défaut, xargs s’attend à ce que les fichiers soient délimités par des espaces, si un espace se trouve dans le nom du fichier, il y aura donc un problème. Ces deux options permettent donc de délimiter les noms des fichiers grâce à un caractère NULL, pensez-y systématiquement pour éviter les erreurs. L’option -r permet d’éviter d’exécuter la commmande passée en argument si la liste des fichiers trouvés est vide.

Pour déplacer toutes les images de votre ~/Desktop dans le dossier ~/Pictures :

find ~/Desktop \( -iname "*.jpg" -o -iname "*.gif" -o -iname "*.png" -o -iname "*.bmp" \) -print0 | xargs -0 mv --target-directory ~/Pictures

N’oubliez pas les parenthèses car le ET est prioritaire sur le OU, car il y a un ET implicite juste avant le -print0.

J’utilise souvent la commande find pour remettre les droits sur les fichiers et les dossiers.

find ~ -type f -print0 | xargs -0 chmod -c 600
find ~ -type d -print0 | xargs -0 chmod -c 700

Astuces

Ne pas afficher les messages d’erreur

Quand la commande find n’a pas les droits pour accéder à un fichier, un message d’erreur s’affiche et risque de polluer l’affichage. Pour éviter d’afficher ces erreurs, il suffit de rediriger stderr vers /dev/null.

find / 2>/dev/null
# avec xargs
find / -print0 2> /dev/null | xargs -0 ls -lh

Trouver et renommer des fichiers contenant des caractères non imprimables

Il peut arriver sous Linux que des fichiers soient formés de caractères non imprimables, pour diverses raisons.
Il faut connaitre l’inode du fichier pour pouvoir le renommer grâce à la commande find, pour cela, il suffit de faire un ls -ali.

find . -inum 120281 -print0 | xargs -0 mv new_file_name

Ignorer des dossiers

Pour ignorer un dossier, on doit utiliser l’option -prune. Cette option est une action qui indique à la commande find de ne pas descendre dans le dossier trouvé. Il faut utiliser l’option -prune en combinaison du OU -o. La partie située avant le -prune est la condition qui indique quel dossier ignorer, la partie droite indique les critères de recherche, dans le cas où on ne souhaite pas mettre de critère à droite mais simplement afficher, il suffit de mettre un -print qui est l’action par défaut de la commande find.

Par exemple, pour trouver tous les fichiers qui ne sont pas dans /proc ou /var, on fait :

find / \( -path /proc -o -path /var \) -prune -o -print

Et pour trouver tous les fichiers non vides, tout en ignorant /proc et /var, on fait :

find / \( -path /proc -o -path /var \) -prune -o ! -empty -print

Pour trouver tous les fichiers non vides de mon répertoire personnel qui ne se trouvent pas dans un dossier caché (commençant par un .), on fait :

find ~ -name ".*" -prune -o ! -empty -print

Limiter la profondeur d’action

Contrairement à la plupart des autres commandes sous GNU Linux, find descend dans les sous-répertoires sans qu’on ait à le lui demander. Parfois, il est possible que l’on souhaite limiter la profondeur maximale ou minimale.

L’option -maxdepth permet de spécifier la profondeur maximale des répertoires dans lesquels on va descendre. Si on indique 0 à cette option, cela signifie que les tests ne vont s’appliquer qu’aux arguments passés à find, testez, vous comprendrez.

find / -maxdepth 2
/boot/map
...
/bin/nc
/bin/ping
/bin/bzcat
...
/var/cache
/var/lock
/var/mail
/var/tmp
/tmp

L’option -mindepth permet de spécifier la profondeur minimale des répertoires dans lesquels find effectuera les tests. Si on indique 1 à cette option, cela signifie que la commande find effectuera les tests sur tous les fichiers sauf à ses arguments.

# n'affichera que le contenu de tous les répertoires personnels
find /home -mindepth 2

Enfin, une dernière option qui peut être intéressante dans certains cas : -depth. Elle permet de procéder au contenu du répertoire avant le répertoire lui-même. Imaginez une arborescence de répertoires vides, ne contenant aucun fichier. Pour les supprimer, il faut d’abord supprimer les répertoires fils. On peut donc le faire avec l’option -depth.

find empty_dirs -depth -print0 | xargs -0 rmdir

Affichage personnalisé

Vous pourrez peut-être apprécier les arguments utilisables avec l’option -printf qui permet de personnaliser l’affichage sur la sortie standard stdout. Cette option, tout comme le printf du C, prend une chaîne en argument, et cette chaîne représente le format de l’affichage. Les arguments possibles sont consultables via un man find.

find /bin -printf "name: %20f - size: %10s\n"
name:                  bin - size:       4096
name:              bzfgrep - size:          6
name:                mount - size:      64112
name:                mkdir - size:      29344
name:                rmdir - size:      23480
name:                which - size:        946
name:               mktemp - size:       6672
name:                   nc - size:         20
name:                 ping - size:      30788

Conclusion

Nous venons de voir un aperçu de la commande find. Il existe bien d’autres options mais il s’agit ici des plus intéressantes. N’hésitez pas à consulter la page de manuel de cette commande vraiment pratique.