RTFM en guise de disclaimer

Si vous ne savez pas que

find / -exec rm {} \;

efface la totalité des fichiers sur lesquels vous avez des droits d'écriture, il est temps de lire la page de man de find!


Recherches multiples

  • pour rechercher des fichiers ? Joker!
    • find -iname '*.exe'

A noter le -iname pour ne pas tenir compte de la casse des fichiers, et les simples quotes qui encadrent la chaine recherchée.

Les simples quotes protègent la chaine et évitent une inteprétation prématurée.

  • quand le joker ne suffit plus
    • pour des fichiers vraiment différents (par exemple, des extensions différentes), on ne peut plus utiliser un simple joker.
    • find -iname '*.exe' -or -iname '*.elf'

semble fonctionner. D'ailleurs ça fonctionne pour l'affichage.

  • mais ... ça ne marchera pas avec un -print ou un -exec
find -iname '*.exe' -or -iname '*.elf' -exec echo "trouvé {}" \;

Cette commande ne ramène que les fichiers avec l'extension .elf car le -exec possède un -and implicite.

Le -or provoque l'évaluation des deux conditions, mais seule la dernière est associée à une action.

On peut simplifier l'opération précédente ainsi:

A -or (B -and C)

les parenthèses sont là pour indiquer la précédence. Même si la condition A est True, elle n'aura pas d'effet visible. A contrario, la condition B est associée à l'action C , et aura (si elle est True) un effet visible.

Il faut opérer un regroupement en utilisant l'opérateur ( ) qui est l' opérateur de combinaison de critères.

find '(' -iname '*.exe' -or -iname '*.elf' ')' -exec echo "trouvé {}" \;

L'opérateur ( ) est placé entre quotes pour éviter que le shell n'interpréte son contenu comme un sous-shell.


Concision et expressions régulières

  • l'exemple précédent est certes sympathique, mais un peu lourd à la lecture, surtout si on ajoute encore une extension
  • les regexs sont un bon moyen de le rendre plus concis. find possède quelques particularités de ce côté.
  • le moteur de find fait que certains caractères des regexs sont évalués comme des caractères normaux:
    • ( , ) et | doivent être préfixés pour être utilisés en tant que groupes et "ou" logique
    • par contre, le point est toujours interprété comme un caractère générique, et il faut le préfixer pour qu'il soit interprété comme un point.
  • ainsi, il faudra écrire:
find -iregex '.*\.\(exe\|elf\|o\)$' -exec rm {} \;

à placer dans la rêgle clean de votre Makefile, pour effacer les exécutables et les fichiers objets.

Enfin, si vous le placez dans un Makefile , n'oubliez pas de doubler le dollar ($$), pour éviter l'interprétation du caractère fin de ligne ($) de la regexp en une variable. Mais ceci est un autre sujet :-)

Dernière chose : le iregex rend insensible à la casse l'évaluation de l'expression régulière.


Se prendre une prune

  • l'astuce du terminateur :
    • quand on recherche un repertoire en particulier, il ne faut pas mettre de '/' terminateur
    • à noter le dot-slash initial "./" quand on recherche à partir du répertoire actuel.
    • find -path ./objets -print
  • bon alors là, c'est facile. On a trouvé le repertoire "objets". Tiens, ça n'affiche que "./objets" d'ailleurs, pas les fichiers.
  • Et si on veut les fichiers du répertoire "objets" ?
  • En fait dans ce dernier cas , le -path ./objets n'est True que pour le répertoire objets , et False autrement (meme pour ./objets/toto)
  • Le -print n'affiche que pour un résultat True , donc il n'affiche que le nom du répertoire et pas son contenu.
  • Faisons encore une expérience:
find '(' -path ./objets -printf 'A: %f
' ')' -or -printf 'B: %f
'

Cette commande affichera un ''A: objets"" pour l'objet lui même (seul élement à remplir la première condition).

Pour tout le reste, la commande affichera un ''B: "" suivi du nom des fichiers.

Ici, le -or est précisé, mais dans la forme habituelle de la commande find, le -and est implicite.

  • Donc, en résumé, quand on a:
    • find -path ./objets -print

nous avons en réalité : find -path ./objets -and -print

Donc si -path est False, le -print n'est pas exécuté et l'expression complète est False.


  • Et la p'tite prune de monsieur ?
    • dans ce cas, -prune est une optimisation qui empêche la descente dans le répertoire spécifié.
    • find -path ./objets -prune -print

Affichera uniquement le nom du répertoire objets.

Bien sûr, on peut utiliser -prune pour exclure des fichiers (-prune renvoie toujours True ce qui est bon à savoir pour résoudre les problèmes de chainage des opérateurs)

find -iname 'objets' -prune -or print

n'affichera pas les fichiers du répertoire objets car le -and implicite concerne le -iname (celui ci est donc pruné et tout le reste imprimé).

Pour récupérer les fichiers de objets, bien sûr c'est find objets -type f

Nous nous sommes un peu perdu en chemin, mais ça valait le coup d'explorer la région :-)


Entre parenthèses

  • Que retenir de tout ça ?
    • La combinaison de critères (le parenthèsage)
    • les opérateurs logique (-and , -or , et la négation ! )

Avec tout ça, on assure le quotidien.

Une dernière astuce pour les gens qui ont un find récent: l'ajout de l'opérateur -delete qui évitera les -exec rm {} désastreux.

Malheureusement, cet opérateur n'est pas disponible sur le find de mon shell MS-Windows (MSys)

Je ne parle pas de la gestion du temps, c'est facile: ça marche par tranche de 24h, en partant de la journée en cours qui vaut 0.


En guise de consolation

On peut faire de grandes choses avec find.

Il faut juste ne pas avoir peur d'avoir mal à la tête.

Merci à Frédéric qui m'a expliqué le plus compliqué, et qui a relu.