Je comprends que ls -R
affiche une liste de répertoires. Mais pourquoi est-ce récursif? Comment la récursivité est-elle utilisée dans le processus?
command-line
ls
Mint.K
la source
la source
ls
rencontre un répertoire, il le répertorie de manière récursive.Réponses:
Tout d’abord, définissons une structure de dossiers arbitraire:
Lorsque nous le faisons
ls
, nous obtenons la sortie du dossier de base uniquement:Cependant, lorsque nous appelons
ls -R
, nous obtenons quelque chose de différent:Comme vous pouvez le constater, il s’exécute
ls
sur le dossier de base, puis sur tous les dossiers enfants. Et tous les dossiers de petits-enfants, ad infinitum. En réalité, la commande parcourt chaque dossier de manière récursive jusqu'à ce qu'il atteigne la fin de l'arborescence. À ce stade, il revient dans une branche de l'arborescence et fait la même chose pour tous les sous-dossiers, le cas échéant.Ou, en pseudo-code:
Et parce que je peux, une implémentation Java de référence de la même chose.
la source
En réalité, vous pouvez poser deux questions étroitement liées.
ls
? D'après votre phrasé ("Comment la récursion est-elle utilisée dans le processus?"), Je pense que cela fait partie de ce que vous voulez savoir. Cette réponse répond à cette question.Pourquoi il est logique
ls
de mettre en œuvre avec une technique récursive:FOLDOC définit la récursion comme:
La manière naturelle d'implémenter
ls
est d'écrire une fonction qui construit une liste d'entrées du système de fichiers à afficher, ainsi qu'un autre code permettant de traiter les arguments de chemin et d'option et d'afficher les entrées à votre guise. Cette fonction est hautement susceptible d'être implémentée de manière récursive.Pendant le traitement des options,
ls
déterminera s'il a été demandé à l'opération récursive (en étant appelé avec l'-R
indicateur). Si tel est le cas, la fonction qui crée une liste d'entrées à afficher s'appellera une fois pour chaque répertoire répertorié, à l'exception de.
et..
. Il peut y avoir des versions distinctes récursives et non récursives de cette fonction, ou la fonction peut vérifier chaque fois si elle est supposée fonctionner de manière récursive.Ubuntu
/bin/ls
, l'exécutable qui s'exécute lorsque vous l'exécutezls
, est fourni par GNU Coreutils et comporte de nombreuses fonctionnalités. En conséquence, son code est un peu plus long et plus compliqué que prévu. Mais Ubuntu contient également une version simplifiée dels
, fournie par BusyBox . Vous pouvez exécuter ceci en tapantbusybox ls
.Comment
busybox ls
utilise la récursivité:ls
dans BusyBox est implémenté danscoreutils/ls.c
. Il contient unescan_and_display_dirs_recur()
fonction appelée pour imprimer une arborescence de répertoires de manière récursive:La ligne où l'appel de fonction récursif a lieu est la suivante:
Voir les appels de fonction récursifs au fur et à mesure qu'ils se produisent:
Vous pouvez le voir en opération si vous exécutez
busybox ls
un débogueur. Commencez par installer les symboles de débogage en activant les packages -dbgsym.ddeb, puis en installant lebusybox-static-dbgsym
package. Installezgdb
aussi bien (c'est le débogueur).Je suggère de déboguer
coreutils ls
sur une arborescence de répertoires simple.Si vous n'en avez pas, créez-en un (cela fonctionne de la même manière que la
mkdir -p
commande dans la réponse de WinEunuuchs2Unix ):Et remplissez-le avec quelques fichiers:
Vous pouvez vérifier les
busybox ls -R foo
travaux comme prévu en produisant cette sortie:Ouvrir
busybox
dans le débogueur:GDB imprimera des informations sur lui-même. Ensuite, il devrait dire quelque chose comme:
(gdb)
est votre invite dans le débogueur. La première chose à faire à GDB à cette invite est de définir un point d'arrêt au début de lascan_and_display_dirs_recur()
fonction:Lorsque vous lancez cela, GDB devrait vous dire quelque chose comme:
Maintenant, indiquez à GDB de s’exécuter
busybox
avec (ou le nom de répertoire de votre choix) comme arguments:ls -R foo
Vous pouvez voir quelque chose comme ça:
Si vous voyez
No such file or directory
, comme ci-dessus, c'est bon. Le but de cette démonstration est simplement de voir quand lascan_and_display_dirs_recur()
fonction a été appelée, ainsi GDB n'a pas besoin d'examiner le code source réel.Notez que le débogueur a atteint le point d'arrêt avant même que les entrées du répertoire aient été imprimées. Il se rompt sur l' entrée de cette fonction, mais le code de cette fonction doit être exécuté pour que tous les répertoires soient énumérés pour l'impression.
Pour dire à GDB de continuer, exécutez:
Chaque fois que vous
scan_and_display_dirs_recur()
appelez, le point d'arrêt sera touché à nouveau afin que vous puissiez voir la récursion en action. Cela ressemble à ceci (y compris l'(gdb)
invite et vos commandes):La fonction a
recur
dans son nom ... BusyBox ne l'utilise-t-elle que lorsque le-R
drapeau est donné? Dans le débogueur, il est facile de savoir:Même sans
-R
, cette implémentation particulière dels
utilise la même fonction pour rechercher les entrées de système de fichiers existantes et les afficher.Lorsque vous voulez quitter le débogueur, dites-lui simplement:
Comment
scan_and_display_dirs_recur()
savoir s'il devrait s'appeler lui-même:En particulier, comment cela fonctionne-t-il différemment lorsque le
-R
drapeau est passé? L'examen du code source (qui peut ne pas être la version exacte sur votre système Ubuntu) révèle qu'il vérifie sa structure de données interneG.all_fmt
, où il stocke les options avec lesquelles il a été appelé:(Si BusyBox a été compilé sans support
-R
, il ne tentera pas non plus d'afficher les entrées du système de fichiers de manière récursive; c'est ce dont il s'agit dans laENABLE_FEATURE_LS_RECURSIVE
partie.)Le
G.all_fmt & DISP_RECURSIVE
code contenant l'appel de fonction récursif n'est exécuté que lorsque true est utilisé.Sinon, la fonction ne s'exécute qu'une fois (par répertoire spécifié sur la ligne de commande).
la source
Quand vous y réfléchissez, "récursif" est logique pour les commandes qui agissent sur les répertoires et leurs fichiers et les répertoires et leurs fichiers et répertoires et leurs fichiers et répertoires et leurs fichiers .........
.... jusqu’à ce que l’arbre entier, à partir du point spécifié, ait été utilisé par la commande, répertoriant dans ce cas le contenu des sous-répertoires de tous les sous-répertoires de tous les sous-répertoires .......... existant sous le répertoire argument (s) de la commande
la source
-R est pour la récursion, qui pourrait être appelé "à plusieurs reprises".
Prenons ce code par exemple:
La
-p
création de répertoires vous permet de créer en masse des répertoires avec une seule commande. Si un ou plusieurs des répertoires du milieu en haut existent déjà, ce n'est pas une erreur et les répertoires du milieu en bas sont créés.Ensuite, la
ls -R
liste récursive répertorie chaque répertoire, en commençant par temp, puis en descendant dans l’arbre, jusqu’à toutes les branches.Regardons maintenant un complément à la
ls -R
commande, c’est-à-dire latree
commande:Comme vous pouvez le voir,
tree
la même chosels -R
est faite, sauf que c'est plus concis et que j'ose dire "plus joli".Voyons maintenant comment supprimer de manière récursive les répertoires que nous venons de créer en une seule commande:
Cela supprime récursivement
temp
et tous les sous-répertoires qu'il contient. c'est-àtemp/a
- dire ,temp/b/1
ettemp/c/1/2
plus les répertoires intermédiaires entre les deux.la source
tree
bien. C'est un excellent outil.Voici une explication simple, qui a du sens, car lorsqu’il s’agit d’afficher le contenu des sous-répertoires, la même fonction sait déjà quoi faire avec un répertoire. Par conséquent, il suffit de s’appeler sur chaque sous-répertoire pour obtenir ce résultat!
En pseudo-code, cela ressemble à ceci:
la source