Entiendo que ls -R
muestra una lista de directorios. ¿Pero por qué es recursivo? ¿Cómo se usa la recursión en el proceso?
command-line
ls
Mint.K
fuente
fuente
ls
encuentra un directorio, enumera recursivamente ese directorio.Respuestas:
En primer lugar, definamos una estructura de carpetas arbitraria:
Cuando lo hacemos
ls
, solo obtenemos la salida de la carpeta base:Sin embargo, cuando llamamos
ls -R
, obtenemos algo diferente:Como puede ver, se ejecuta
ls
en la carpeta base y luego en todas las carpetas secundarias. Y todas las carpetas de nietos, hasta el infinito. Efectivamente, el comando pasa por cada carpeta de forma recursiva hasta que llega al final del árbol de directorios. En ese punto, vuelve a subir una rama en el árbol y hace lo mismo para cualquier subcarpeta, si corresponde.O, en pseudocódigo:
Y porque puedo, una implementación Java de referencia de la misma.
fuente
En efecto, hay dos preguntas estrechamente relacionadas que puede estar haciendo.
ls
? Por tu fraseo ("¿Cómo se usa la recursividad en el proceso?"), Creo que esto es parte de lo que quieres saber. Esta respuesta aborda esa pregunta.Por qué tiene sentido
ls
implementarse con una técnica recursiva:FOLDOC define la recursividad como:
La forma natural de implementar
ls
es escribir una función que construya una lista de entradas del sistema de archivos para mostrar, y otro código para procesar argumentos de ruta y opciones y para mostrar las entradas como se desee. Es muy probable que esa función se implemente recursivamente.Durante el procesamiento de opciones,
ls
determinará si se le ha pedido que opere recursivamente (al ser invocado con la-R
bandera). Si es así, la función que crea una lista de entradas para mostrar se llamará a sí misma una vez por cada directorio que enumere, excepto.
y..
. Puede haber versiones recursivas y no recursivas por separado de esta función, o la función puede verificar cada vez si se supone que está funcionando recursivamente.Ubuntu's
/bin/ls
, el ejecutable que se ejecuta cuando se ejecutals
, es proporcionado por GNU Coreutils , y tiene muchas características. Como resultado, su código es algo más largo y más complicado de lo que cabría esperar. Pero Ubuntu también contiene una versión más simple dels
, proporcionada por BusyBox . Puede ejecutar esto escribiendobusybox ls
.Cómo
busybox ls
usa la recursividad:ls
en BusyBox se implementa encoreutils/ls.c
. Contiene unascan_and_display_dirs_recur()
función que se invoca para imprimir un árbol de directorios de forma recursiva:La línea donde tiene lugar la llamada a la función recursiva es:
Ver la función recursiva llama a medida que ocurren:
Puede ver esto en funcionamiento si se ejecuta
busybox ls
en un depurador. En primer lugar instalar los símbolos de depuración por permitir paquetes -dbgsym.ddeb y después de instalar elbusybox-static-dbgsym
paquete. Instalargdb
también (ese es el depurador).Sugiero depurar
coreutils ls
en un árbol de directorios simple.Si no tiene uno a mano, haga uno (esto funciona de la misma manera que el
mkdir -p
comando en la respuesta de WinEunuuchs2Unix ):Y llenarlo con algunos archivos:
Puede verificar los
busybox ls -R foo
trabajos como se esperaba, produciendo esta salida:Abrir
busybox
en el depurador:GDB imprimirá alguna información sobre sí mismo. Entonces debería decir algo como:
(gdb)
es su aviso en el depurador. Lo primero que le dirá a GDB que haga en este indicador es establecer un punto de interrupción al comienzo de lascan_and_display_dirs_recur()
función:Cuando ejecuta eso, GDB debería decirle algo como:
Ahora dígale a GDB que se ejecute
busybox
con (o cualquier nombre de directorio que desee) como sus argumentos:ls -R foo
Puede ver algo como esto:
Si ve
No such file or directory
, como arriba, está bien. El propósito de esta demostración es simplemente ver cuándoscan_and_display_dirs_recur()
se ha llamado a la función, por lo que GDB no necesita examinar el código fuente real.Observe que el depurador alcanzó el punto de interrupción incluso antes de que se imprimieran las entradas de directorio. Se rompe en el entrace a esa función, pero el código de esa función debe funcionar para todos los directorios que se enumeran para imprimir.
Para decirle a GDB que continúe, ejecute:
Cada vez que
scan_and_display_dirs_recur()
se llama, el punto de interrupción se alcanzará nuevamente, por lo que podrá ver la recursión en acción. Se ve así (incluyendo el(gdb)
indicador y sus comandos):La función tiene
recur
su nombre ... ¿BusyBox solo la usa cuando-R
se da la bandera? En el depurador, esto es fácil de descubrir:Incluso sin
-R
, esta implementación particular dels
utiliza la misma función para averiguar qué entradas del sistema de archivos existen y mostrarlas.Cuando desee salir del depurador, solo dígale:
Cómo
scan_and_display_dirs_recur()
sabe si debería llamarse a sí mismo:Específicamente, ¿cómo funciona de manera diferente cuando
-R
se pasa la bandera? El examen del código fuente (que puede no ser la versión exacta en su sistema Ubuntu) revela que verifica su estructura de datos internaG.all_fmt
, donde almacena las opciones con las que se ha invocado:(Si BusyBox ha sido compilado sin soporte
-R
, tampoco intentará mostrar las entradas del sistema de archivos de forma recursiva; de eso se trata laENABLE_FEATURE_LS_RECURSIVE
parte).Solo cuando
G.all_fmt & DISP_RECURSIVE
es verdadero se ejecuta el código que contiene la llamada de función recursiva.De lo contrario, la función solo se ejecuta una vez (por directorio especificado en la línea de comando).
fuente
Cuando lo piensa, "recursivo" tiene sentido para los comandos que actúan sobre directorios y sus archivos y directorios y sus archivos y directorios y sus archivos y directorios y sus archivos .........
.... hasta que el comando haya operado todo el árbol desde el punto especificado hacia abajo, en este caso enumerando el contenido de cualquier subdirectorio de cualquier subdirectorio de cualquier subdirectorio .......... que exista bajo el argumento (s) del comando
fuente
-R es para recursión, que podría llamarse libremente "repetidamente".
Tome este código por ejemplo:
La
-p
creación de directorios le permite crear directorios en masa con un solo comando. Si ya existen uno o más de los directorios superior-medio, no es un error y se crean los directorios medio-inferior.Luego,
ls -R
recursivamente enumera todos los directorios, comenzando con temp y trabajando en el árbol hasta todas las ramas.Ahora veamos un complemento al
ls -R
comando, es decir, eltree
comando:Como puede ver,
tree
logra lo mismo quels -R
excepto es más conciso y me atrevo a decir "más bonito".Ahora veamos cómo eliminar recursivamente los directorios que acabamos de crear en un comando simple:
Esto elimina de forma recursiva
temp
y todos los subdirectorios debajo de él. es decirtemp/a
,temp/b/1
ytemp/c/1/2
más los directorios intermedios en el medio.fuente
tree
. Es una gran herramienta.Aquí hay una explicación simple, tiene sentido porque cuando se trata de mostrar el contenido de subdirectorios, la misma función ya sabe qué hacer con un directorio. ¡Por lo tanto, solo necesita llamarse a sí mismo en cada subdirectorio para obtener ese resultado!
En pseudocódigo se parece a esto:
fuente