Entiendo que ls -Rmuestra 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

lsencuentra 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
lsen 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
lsimplementarse con una técnica recursiva:FOLDOC define la recursividad como:
La forma natural de implementar
lses 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,
lsdeterminará si se le ha pedido que opere recursivamente (al ser invocado con la-Rbandera). 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 lsusa la recursividad:lsen 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 lsen un depurador. En primer lugar instalar los símbolos de depuración por permitir paquetes -dbgsym.ddeb y después de instalar elbusybox-static-dbgsympaquete. Instalargdbtambién (ese es el depurador).Sugiero depurar
coreutils lsen un árbol de directorios simple.Si no tiene uno a mano, haga uno (esto funciona de la misma manera que el
mkdir -pcomando en la respuesta de WinEunuuchs2Unix ):Y llenarlo con algunos archivos:
Puede verificar los
busybox ls -R footrabajos como se esperaba, produciendo esta salida:Abrir
busyboxen 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
busyboxcon (o cualquier nombre de directorio que desee) como sus argumentos:ls -R fooPuede 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
recursu nombre ... ¿BusyBox solo la usa cuando-Rse da la bandera? En el depurador, esto es fácil de descubrir:Incluso sin
-R, esta implementación particular delsutiliza 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
-Rse 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_RECURSIVEparte).Solo cuando
G.all_fmt & DISP_RECURSIVEes 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
-pcreació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 -Rrecursivamente enumera todos los directorios, comenzando con temp y trabajando en el árbol hasta todas las ramas.Ahora veamos un complemento al
ls -Rcomando, es decir, eltreecomando:Como puede ver,
treelogra lo mismo quels -Rexcepto 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
tempy todos los subdirectorios debajo de él. es decirtemp/a,temp/b/1ytemp/c/1/2má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