Comment parcourir une arborescence de répertoires sous Linux

Publié: 2022-07-21
Ordinateur portable Linux affichant une invite bash
fatmawati achmad zaenuri/Shutterstock.com

Les répertoires sur Linux vous permettent de regrouper des fichiers dans des collections distinctes et séparées. L'inconvénient est qu'il devient fastidieux de passer d'un répertoire à l'autre pour effectuer une tâche répétitive. Voici comment automatiser cela.

Tout sur les répertoires

La première commande que vous apprenez lorsque vous découvrez Linux est probablement ls , mais cd ne sera pas loin derrière. Comprendre les répertoires et comment s'y déplacer, en particulier les sous-répertoires imbriqués, est un élément fondamental pour comprendre comment Linux s'organise et comment vous pouvez organiser votre propre travail en fichiers, répertoires et sous-répertoires.

La structure du répertoire Linux, expliquée
CONNEXION La structure du répertoire Linux, expliquée

Comprendre le concept d'arborescence de répertoires - et comment se déplacer entre eux - est l'un des nombreux petits jalons que vous franchissez lorsque vous vous familiarisez avec le paysage de Linux. L'utilisation de cd avec un chemin vous amène à ce répertoire. Des raccourcis comme cd ~ ou cd seul vous ramènent à votre répertoire personnel, et cd .. vous fait monter d'un niveau dans l'arborescence des répertoires. Simple.

Cependant, il n'existe pas de moyen aussi simple d'exécuter une commande dans tous les répertoires d'une arborescence de répertoires. Il existe différentes manières d'obtenir cette fonctionnalité, mais il n'existe pas de commande Linux standard dédiée à cet effet.

Certaines commandes, telles que ls , ont des options de ligne de commande qui les obligent à fonctionner de manière récursive , ce qui signifie qu'elles commencent dans un répertoire et parcourent méthodiquement toute l'arborescence des répertoires sous ce répertoire. Pour ls , c'est l'option -R (récursive).

Si vous devez utiliser une commande qui ne prend pas en charge la récursivité, vous devez fournir vous-même la fonctionnalité récursive. Voici comment procéder.

CONNEXION: 37 commandes Linux importantes que vous devez connaître

La commande arbre

La commande tree ne nous aidera pas dans la tâche à accomplir, mais elle permet de voir facilement la structure d'une arborescence de répertoires. Il dessine l'arborescence dans une fenêtre de terminal afin que nous puissions obtenir un aperçu instantané des répertoires et sous-répertoires qui composent l'arborescence des répertoires et de leurs positions relatives dans l'arborescence.

Vous devrez installer tree .

Sur Ubuntu, vous devez taper :

 arbre d'installation sudo apt 

Installer l'arborescence sur Ubuntu

Sur Fedora, utilisez :

 arbre d'installation sudo dnf 

Installer l'arborescence sur Fedora

Sur Manjaro, la commande est :

 sudo pacman -Sy arbre 

Installation d'arbre sur Manjaro

L'utilisation de tree sans paramètre dessine l'arbre sous le répertoire courant.

 arbre 

Exécution de l'arborescence dans le répertoire courant

Vous pouvez passer un chemin vers l' tree sur la ligne de commande.

 travail des arbres 

Exécution de l'arborescence sur un répertoire spécifié

L'option -d (répertoires) exclut les fichiers et affiche uniquement les répertoires.

 arbre -d travail 

Exécution de l'arborescence et affichage uniquement des répertoires

C'est le moyen le plus pratique d'avoir une vue claire de la structure d'une arborescence de répertoires. L'arborescence de répertoires présentée ici est celle utilisée dans les exemples suivants. Il y a cinq fichiers texte et huit répertoires.

Ne pas analyser la sortie de ls aux répertoires Traverse

Votre première pensée pourrait être, si ls peut traverser récursivement une arborescence de répertoires, pourquoi ne pas utiliser ls pour faire exactement cela et diriger la sortie vers d'autres commandes qui analysent les répertoires et effectuent certaines actions ?

L'analyse de la sortie de ls est considérée comme une mauvaise pratique. En raison de la capacité de Linux à créer des noms de fichiers et de répertoires contenant toutes sortes de caractères étranges, il devient très difficile de créer un analyseur générique et universellement correct.

Vous ne créerez peut-être jamais sciemment un nom de répertoire aussi absurde que celui-ci, mais une erreur dans un script ou une application pourrait le faire.

Un nom de répertoire bizarre

L'analyse de noms de fichiers et de répertoires légitimes mais mal pris en compte est sujette aux erreurs. Il existe d'autres méthodes que nous pouvons utiliser qui sont plus sûres et beaucoup plus robustes que de s'appuyer sur l'interprétation de la sortie de ls .

Utilisation de la commande de recherche

La commande find a des capacités récursives intégrées, et elle a également la capacité d'exécuter des commandes pour nous. Cela nous permet de construire de puissants one-liners. Si c'est quelque chose que vous voudrez probablement utiliser à l'avenir, vous pouvez transformer votre one-liner en alias ou en fonction shell.

Cette commande parcourt de manière récursive l'arborescence des répertoires, à la recherche de répertoires. Chaque fois qu'il trouve un répertoire, il imprime le nom du répertoire et répète la recherche à l'intérieur de ce répertoire. Après avoir terminé la recherche d'un répertoire, il quitte ce répertoire et reprend la recherche dans son répertoire parent.

 trouver le travail -type d -execdir echo "Dans :" {} \ ; 

utiliser la commande find pour rechercher récursivement des répertoires

Vous pouvez voir par l'ordre dans lequel les répertoires sont répertoriés, comment la recherche progresse dans l'arborescence. En comparant la sortie de la commande tree à la sortie de la ligne find , vous verrez comment find recherche tour à tour chaque répertoire et sous-répertoire jusqu'à ce qu'il rencontre un répertoire sans sous-répertoires. Il remonte ensuite d'un niveau et reprend la recherche à ce niveau.

Voici comment la commande est composée.

  • find : La commande de find .
  • work : Le répertoire dans lequel commencer la recherche. Il peut s'agir d'un chemin.
  • -type d : Nous recherchons des répertoires.
  • -execdir : Nous allons exécuter une commande dans chaque répertoire que nous trouvons.
  • echo "In:" {} : Ceci est la commande., Nous renvoyons simplement le nom du répertoire à la fenêtre du terminal. Le "{}" contient le nom du répertoire courant.
  • \ ; : Il s'agit d'un point-virgule utilisé pour terminer la commande. Nous devons lui échapper avec la barre oblique inverse afin que Bash ne l'interprète pas directement.

Avec une légère modification, nous pouvons faire en sorte que la commande find renvoie des fichiers correspondant à un indice de recherche. Nous devons inclure l'option -name et un indice de recherche. Dans cet exemple, nous recherchons des fichiers texte qui correspondent à "*.txt" et renvoyons leur nom à la fenêtre du terminal.

 find work -name "*.txt" -type f -execdir echo "Trouvé :" {} \ ; 

utiliser la commande find pour rechercher récursivement des fichiers

Que vous recherchiez des fichiers ou des répertoires dépend de ce que vous voulez réaliser. Pour exécuter une commande dans chaque répertoire , utilisez -type d . Pour exécuter une commande sur chaque fichier correspondant , utilisez -type f .

Cette commande compte les lignes de tous les fichiers texte du répertoire de départ et des sous-répertoires.

 trouver le travail -nom "*.txt" -type f -execdir wc -l {} \; 

Utiliser find avec la commande wc

CONNEXION: Comment utiliser la commande find sous Linux

Parcourir les arborescences de répertoires avec un script

Si vous avez besoin de parcourir des répertoires à l'intérieur d'un script, vous pouvez utiliser la commande find dans votre script. Si vous devez ou souhaitez simplement effectuer les recherches récursives vous-même, vous pouvez également le faire.

 #!/bin/bash

shopt -s pointglob nullglob

fonction récursive {

  local répertoire_actuel répertoire_ou_fichier

  pour rép_actuel dans $1 ; fais

    echo "Commande de répertoire pour :" $current_dir

    pour dir_or_file dans "$current_dir"/* ; fais

      if [[ -d $dir_or_file ]] ; alors
        récursif "$dir_or_file"
      autre
        wc $dir_or_file
      Fi
    Fini
  Fini
}

"$1" récursif

Copiez le texte dans un éditeur et enregistrez-le sous "recurse.sh", puis utilisez la commande chmod pour le rendre exécutable.

 chmod +x recurse.sh 

Rendre le script recurse.sh exécutable

Le script définit deux options de shell, dotglob et nullglob .

Le paramètre dotglob signifie que les noms de fichiers et de répertoires commencent par un point " . ” sera renvoyé lorsque les termes de recherche génériques seront développés. Cela signifie effectivement que nous incluons des fichiers et des répertoires cachés dans nos résultats de recherche.

Le paramètre nullglob signifie que les modèles de recherche qui ne trouvent aucun résultat sont traités comme une chaîne vide ou nulle. Ils n'utilisent pas par défaut le terme de recherche lui-même. En d'autres termes, si nous recherchons tout dans un répertoire en utilisant le caractère générique astérisque " * ", mais qu'il n'y a aucun résultat, nous recevrons une chaîne nulle au lieu d'une chaîne contenant un astérisque. Cela empêche le script d'essayer par inadvertance d'ouvrir un répertoire appelé "*" ou de traiter "*" comme un nom de fichier.

Ensuite, il définit une fonction appelée recursive . C'est là que les choses intéressantes se passent.

Deux variables sont déclarées, appelées current_dir et dir_or_file . Ce sont des variables locales et ne peuvent être référencées que dans la fonction.

Une variable appelée $1 est également utilisée dans la fonction. C'est le premier (et le seul) paramètre passé à la fonction lorsqu'elle est appelée.

Abécédaire : Boucles Bash : pour, pendant et jusqu'à
CONNEXION Primer : Boucles Bash : pour, pendant et jusqu'à

Le script utilise deux boucles for , l'une imbriquée dans l'autre. La première boucle for (externe) est utilisée pour deux choses.

La première consiste à exécuter la commande que vous souhaitez exécuter dans chaque répertoire. Tout ce que nous faisons ici est de renvoyer le nom du répertoire à la fenêtre du terminal. Vous pouvez bien sûr utiliser n'importe quelle commande ou séquence de commandes, ou appeler une autre fonction de script.

La deuxième chose que fait la boucle for externe est de vérifier tous les objets du système de fichiers qu'elle peut trouver, qui seront soit des fichiers, soit des répertoires. C'est le but de la boucle for interne. À son tour, chaque nom de fichier ou de répertoire est passé dans la variable dir_or_file .

La variable dir_or_file est ensuite testée dans une instruction if pour voir s'il s'agit d'un répertoire.

  • Si c'est le cas, la fonction s'appelle et passe le nom du répertoire en paramètre.
  • Si la variable dir_or_file n'est pas un répertoire, alors ce doit être un fichier. Toutes les commandes que vous souhaitez appliquer au fichier peuvent être appelées à partir de la clause else de l'instruction if . Vous pouvez également appeler une autre fonction dans le même script.

La dernière ligne du script appelle la fonction recursive et transmet le premier paramètre de ligne de commande $1 comme répertoire de départ dans lequel effectuer la recherche. C'est ce qui lance l'ensemble du processus.

Exécutons le script.

 ./recurse.sh fonctionne 

Traitement des répertoires du moins profond au plus profond

Les répertoires sont parcourus, et le point du script où une commande serait exécutée dans chaque répertoire est indiqué par les lignes « Directory command for: ». La commande wc est exécutée sur les fichiers trouvés pour compter les lignes, les mots et les caractères.

Le premier répertoire traité est "work", suivi de chaque branche de répertoire imbriquée de l'arborescence.

Un point intéressant à noter est que vous pouvez modifier l'ordre dans lequel les répertoires sont traités, en déplaçant les commandes spécifiques au répertoire d'être au-dessus de la boucle interne pour être en dessous.

Déplaçons la ligne "Directory command for:" après la done de la boucle for interne.

 #!/bin/bash

shopt -s pointglob nullglob

fonction récursive {

  local répertoire_actuel répertoire_ou_fichier

  pour rép_actuel dans $1 ; fais

    pour dir_or_file dans "$current_dir"/* ; fais

      if [[ -d $dir_or_file ]] ; alors
        récursif "$dir_or_file"
      autre
        wc $dir_or_file
      Fi

    Fini

    echo "Commande de répertoire pour :" $current_dir

  Fini
}

"$1" récursif

Maintenant, nous allons exécuter le script une fois de plus.

 ./recurse.sh fonctionne 

Traitement des répertoires du plus profond au moins profond

Cette fois, les commandes sont appliquées aux répertoires depuis les niveaux les plus profonds en premier, en remontant les branches de l'arborescence. Le répertoire passé en paramètre au script est traité en dernier.

S'il est important que les répertoires plus profonds soient traités en premier, voici comment vous pouvez le faire.

La récursivité est bizarre

C'est comme vous appeler sur votre propre téléphone et vous laisser un message pour vous dire quand vous vous rencontrerez à plusieurs reprises.

Cela peut demander un certain effort avant de saisir ses avantages, mais lorsque vous le ferez, vous verrez que c'est une manière programmatiquement élégante de s'attaquer à des problèmes difficiles.

CONNEXION: Qu'est-ce que la récursivité dans la programmation et comment l'utilisez-vous?