HOWTO · Bash
Exécutez la commande find -exec dans Bash
Cet article explique comment l’action -exec de find applique une commande aux chemins sélectionnés ; pour rechercher dans le contenu des fichiers, utilisez grep.
Sur cette page
find sélectionne des chemins dans le système de fichiers ; grep recherche dans le contenu des fichiers. L’action -exec relie les deux en transmettant chaque chemin sélectionné comme argument à une autre commande. Ce guide présente une syntaxe réutilisable, la recherche dans le contenu des fichiers, la différence entre une exécution par correspondance et le traitement de plusieurs chemins par lots, ainsi que des opérations prudentes sur les fichiers.
Fonctionnement de find -exec
find part du répertoire que vous indiquez, évalue des critères comme le type, le nom, l’âge ou la taille, puis parcourt les chemins correspondants. Avec -exec, la commande choisie est exécutée et chaque chemin correspondant remplace {}. Le chemin est transmis comme argument : les espaces, tabulations, guillemets et caractères génériques d’un nom de fichier ne sont donc pas réinterprétés par un shell. Cette méthode est plus sûre que de construire une chaîne de commande ou de transmettre à une autre commande des noms séparés par des retours à la ligne.
La recherche et l’action sont deux opérations distinctes : un critère comme -name '*.txt' sélectionne des fichiers, tandis qu’une commande comme grep lit leur contenu. Ajoutez -type f si l’action doit s’appliquer uniquement aux fichiers ordinaires. Par défaut, find prend aussi en compte les répertoires ; choisissez donc des critères adaptés au type d’entrée attendu par la commande.
Syntaxe de base de find -exec
La forme réutilisable est find STARTING_PATH TESTS -exec COMMAND {} \;. STARTING_PATH indique l’arborescence à parcourir ; les critères déterminent les chemins transmis à l’action ; COMMAND et ses options définissent l’opération ; et {} indique où find insère un chemin. Dans un shell interactif, écrivez le terminateur sous la forme \; afin que le shell transmette un point-virgule littéral à find. Sans cet échappement ni guillemets, le shell interprète le point-virgule comme un séparateur de commandes.
Mettez entre guillemets les motifs de nom de fichier comme '*.txt'. Les guillemets demandent au shell de transmettre le motif tel quel ; find peut alors comparer les noms à chaque chemin parcouru, au lieu que le motif soit développé en fonction des fichiers du répertoire courant. Pour les chemins commençant par un tiret, indiquez explicitement un répertoire de départ, par exemple ./-archive, afin qu’ils ne soient pas confondus avec des options de commande.
Exécutez cet exemple :
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
set -eu
root=$(mktemp -d)
trap 'rm -rf "$root"' EXIT
mkdir -p "$root/notes"
printf 'report: first\nkeep this line\n' > "$root/notes/weekly report.txt"
printf 'draft only\n' > "$root/notes/draft.txt"
find "$root" -type f -name '*.txt' -exec grep -nH 'report' {} +
L’exemple crée un petit répertoire, ne recherche que des fichiers texte et demande à grep d’afficher les numéros des lignes correspondantes et les noms des fichiers. -H maintient l’affichage du nom de fichier même lorsqu’une invocation ne reçoit qu’un seul chemin. Le répertoire temporaire est supprimé à la fermeture du shell. Cet exemple peut être exécuté ; aucun résultat capturé n’est affirmé ici.
Rechercher dans le contenu des fichiers avec find et grep
Pour rechercher du texte sous /documents, utilisez find /documents -type f -name '*.txt' -exec grep -nH 'report' {} +. find sélectionne les fichiers texte susceptibles de correspondre, et grep affiche chaque ligne correspondante avec son chemin et son numéro de ligne. Utilisez grep -l à la place de -nH si vous avez seulement besoin des noms des fichiers contenant une correspondance. Un fichier peut contenir plusieurs lignes correspondantes ; avec l’affichage par ligne, son chemin peut donc apparaître plusieurs fois.
La chaîne recherchée est transmise comme argument unique, car elle est entre guillemets. Pour une expression régulière, définissez-la soigneusement ; pour une chaîne littérale fixe, grep -F évite d’interpréter les métacaractères des expressions régulières. Une recherche de texte peut échouer à lire un fichier en raison de ses permissions ou de son encodage. Si vous automatisez la commande, tenez compte de ses messages d’erreur et de son code de sortie. Aucun chemin d’exemple n’est indiqué ici, car les résultats dépendent des fichiers présents dans le répertoire du lecteur.
Choisir entre ; et +
Avec -exec COMMAND {} \;, find exécute la commande séparément pour chaque chemin correspondant. Cette forme est facile à comprendre et convient aux commandes conçues pour traiter un chemin à la fois. Le point-virgule échappé pour le shell termine la définition de l’action ; il ne fait pas partie de la commande exécutée.
Avec -exec COMMAND {} +, find transmet plusieurs chemins trouvés à chaque invocation de la commande, en les répartissant en groupes qui respectent la limite de taille des arguments du système. Placez {} une seule fois, comme dernier argument de la commande, juste avant +. Le traitement par lots réduit souvent le coût de démarrage des processus pour des outils comme grep, mais il ne change pas ce que ces outils font à chaque fichier et ne convient pas aux commandes dont le fonctionnement dépend de la réception d’un seul chemin. Le signe plus est transmis directement à find ; il n’a pas besoin d’être échappé pour le shell.
Exécuter en toute sécurité d’autres commandes sur les fichiers trouvés
Avant de supprimer d’anciens journaux, commencez par remplacer l’action par -print et examinez les chemins affichés : find /var/log -type f -name '*.log' -mtime +30 -print. Le critère -mtime +30 sélectionne les fichiers dont la date de modification remonte à plus de 30 périodes complètes de 24 heures ; il ne signifie pas « antérieur au trentième jour du mois ». Après avoir vérifié la sélection et obtenu les permissions nécessaires, GNU et de nombreuses autres implémentations de find prennent en charge -delete, comme dans find /var/log -type f -name '*.log' -mtime +30 -delete. Cette commande supprime les fichiers sans possibilité de les récupérer ; vérifiez donc le répertoire de départ et les critères avant de l’utiliser.
Pour déplacer des fichiers ordinaires de plus de 100 mébioctets depuis un répertoire de téléchargements, examinez d’abord find /downloads -type f -size +100M -print. Si la liste convient et que /archive/ existe sur le même système avec des permissions adaptées, une action fichier par fichier est find /downloads -type f -size +100M -exec mv -- {} /archive/ \;. Le critère de taille +100M utilise les unités de find et arrondit à l’unité supérieure ; vérifiez les conventions de l’implémentation si un seuil exact en octets est nécessaire. Un déplacement peut écraser des fichiers ou créer des conflits de noms dans la destination ; vérifiez donc les noms de base en double avant de lancer la commande. Dans les deux cas, limitez soigneusement les critères de sélection et examinez la prévisualisation avant de modifier les fichiers.