Retour au cours

find xargs

Objectifs

  • Trouver des fichiers et dossiers en utilisant des critères précis (nom, type, taille, date) avec find.
  • Exécuter une commande sur chaque fichier trouvé en utilisant l’option -exec de find.
  • Construire des commandes complexes en combinant la sortie de find avec xargs.
  • Comprendre pourquoi la combinaison find ... -print0 | xargs -0 ... est essentielle pour la robustesse.

Explications détaillées

Notions clés

find : Le chercheur de fichiers récursif

find est un outil extrêmement puissant pour rechercher des fichiers et des dossiers à partir d’un point de départ, de manière récursive. Sa force réside dans ses “prédicats”, qui sont des conditions de recherche.

Syntaxe de base : find [chemin_de_depart] [expression_de_test] [action]

Tests courants :

  • -name "motif" : Cherche par nom. Le motif peut contenir des jokers (*, ?). Doit être cité.
  • -iname "motif" : Comme -name, mais ignore la casse.
  • -type f : Ne trouve que les fichiers.
  • -type d : Ne trouve que les dossiers.
  • -size +10M : Fichiers de plus de 10 mégaoctets. (- pour moins, k pour ko, G pour Go).
  • -mtime -7 : Fichiers modifiés il y a moins de 7 jours. (+7 pour plus de 7 jours).
  • -empty : Fichiers ou dossiers vides.

Actions courantes :

  • -print : L’action par défaut. Affiche le chemin complet.
  • -delete : Supprime les fichiers trouvés. À utiliser avec une extrême prudence.
  • -exec commande {} \; : Exécute commande pour chaque fichier trouvé.
    • {} est remplacé par le chemin du fichier.
    • \; est obligatoire pour marquer la fin de la commande.
    • C’est sûr, mais lent, car un processus est lancé pour chaque fichier.
  • -exec commande {} + : Regroupe les fichiers trouvés et exécute la commande une seule fois avec un maximum d’arguments. C’est beaucoup plus efficace.

xargs : Construire des commandes à partir d’un flux

xargs est un outil qui lit du texte depuis l’entrée standard et l’utilise pour construire et exécuter des lignes de commande. C’est le partenaire naturel de find.

find . -name "*.txt" | xargs rm

Le problème des noms de fichiers

Que se passe-t-il si un nom de fichier contient un espace, comme "mon rapport.txt" ? La commande find . -name "*.txt" | xargs rm échouera, car xargs verra mon, rapport.txt comme deux arguments distincts.

La solution robuste : \0

Pour résoudre ce problème, on utilise un caractère spécial qui ne peut pas exister dans un nom de fichier : le caractère nul (\0).

  1. find ... -print0 : find utilise \0 comme séparateur au lieu d’un saut de ligne.
  2. xargs -0 ... : xargs lit son entrée en utilisant \0 comme séparateur.

Cette combinaison est la seule manière 100% fiable de passer une liste de fichiers de find à xargs.

Syntaxe / Usages

# Trouver tous les fichiers .log dans le dossier courant et ses sous-dossiers
find . -type f -name "*.log"

# Trouver et supprimer tous les fichiers temporaires (.tmp) modifiés il y a plus de 30 jours
find /tmp -type f -name "*.tmp" -mtime +30 -delete

# Compter le nombre de lignes de tous les fichiers .c (lent mais sûr)
find . -name "*.c" -exec wc -l {} \;

# Même chose, mais beaucoup plus rapide
find . -name "*.c" -exec wc -l {} +

# Changer les permissions de tous les scripts .sh (méthode xargs robuste)
find . -type f -name "*.sh" -print0 | xargs -0 chmod +x

Exemples

# Créons un environnement de test
mkdir -p demo_find/dossier_avec_espace
touch demo_find/a.txt "demo_find/dossier_avec_espace/un fichier.log" demo_find/b.txt

cd demo_find

# 1. Problème classique
# 'ls' sera appelé avec "dossier_avec_espace/un", "fichier.log", etc.
find . -type f | xargs ls -l # -> Erreur ou comportement incorrect

# 2. Solution robuste
find . -type f -print0 | xargs -0 ls -l
# -> Affiche correctement les informations pour "un fichier.log"

# 3. Supprimer tous les fichiers .txt
# Dry run (test à blanc) en remplaçant 'rm' par 'echo'
find . -type f -name "*.txt" -print0 | xargs -0 echo rm
# Si la liste est correcte, on exécute la vraie commande
find . -type f -name "*.txt" -print0 | xargs -0 rm

Bonnes pratiques

  • Adoptez find ... -print0 | xargs -0 ... comme un réflexe. C’est la garantie que vos scripts ne casseront pas sur des noms de fichiers exotiques.
  • Avant d’exécuter une commande destructive (rm, mv, …), faites toujours un “dry run” en remplaçant la commande par echo pour vérifier ce qui sera exécuté.
  • Pour des recherches simples dans l’arborescence actuelle, le globbing étendu de Bash 4+ (shopt -s globstar; ls **/*.txt) peut être une alternative plus simple.

Pièges courants

  • Ne pas utiliser -print0 et -0. C’est la source de 99% des problèmes avec find | xargs.
  • Oublier de citer le motif de -name : find . -name *.txt sera interprété par le shell avant find si des fichiers .txt sont dans le dossier courant. Il faut find . -name "*.txt".
  • Complexité des prédicats : find permet des logiques -and (implicite), -or, -not, qui peuvent devenir complexes à lire.

Exercices

  1. Chasse aux gros fichiers :

    • Écrivez une commande find qui liste tous les fichiers de plus de 50 Mo dans votre dossier personnel (~).
  2. Nettoyage de dossiers vides :

    • Écrivez une commande find pour trouver et supprimer tous les dossiers vides dans votre projet.
    • Faites un “dry run” avec echo avant de lancer le -delete.
  3. Recherche de texte récursive et robuste :

    • Écrivez une seule ligne de commande qui cherche la chaîne de caractères “TODO” (insensible à la casse) dans tous les fichiers .py de votre projet.
    • La commande doit être robuste aux noms de fichiers contenant des espaces.
    • (Indice : grep -i "TODO").