Cómo recorrer un árbol de directorios en Linux
Publicado: 2022-07-21
Los directorios en Linux le permiten agrupar archivos en colecciones distintas y separadas. La desventaja es que se vuelve tedioso moverse de un directorio a otro para realizar una tarea repetitiva. Aquí se explica cómo automatizar eso.
Todo sobre directorios
El primer comando que aprende cuando se le presenta Linux es probablemente ls
, pero cd
no se queda atrás. Comprender los directorios y cómo moverse por ellos, particularmente los subdirectorios anidados, es una parte fundamental para comprender cómo se organiza Linux y cómo puede organizar su propio trabajo en archivos, directorios y subdirectorios.
Comprender el concepto de un árbol de directorios, y cómo moverse entre ellos, es uno de los muchos pequeños hitos que supera a medida que se familiariza con el panorama de Linux. Usar cd
con una ruta lo lleva a ese directorio. Los accesos directos como cd ~
o cd
solo lo llevan de vuelta a su directorio de inicio y cd ..
lo sube un nivel en el árbol de directorios. Simple.
Sin embargo, no existe un medio igualmente simple de ejecutar un comando en todos los directorios de un árbol de directorios. Hay diferentes formas en que podemos lograr esa funcionalidad, pero no hay un comando estándar de Linux dedicado a ese propósito.
Algunos comandos, como ls
, tienen opciones de línea de comandos que los obligan a operar de forma recursiva , lo que significa que comienzan en un directorio y trabajan metódicamente en todo el árbol de directorios debajo de ese directorio. Para ls
, es la opción -R
(recursiva).
Si necesita usar un comando que no admite la recursividad, debe proporcionar la funcionalidad recursiva usted mismo. Así es como se hace.
RELACIONADO: 37 comandos importantes de Linux que debe conocer
El comando del árbol
El comando tree
no nos ayudará con la tarea en cuestión, pero facilita ver la estructura de un árbol de directorios. Dibuja el árbol en una ventana de terminal para que podamos obtener una visión general instantánea de los directorios y subdirectorios que componen el árbol de directorios y sus posiciones relativas en el árbol.
Necesitarás instalar tree
.
En Ubuntu necesitas escribir:
árbol de instalación de sudo apt
En Fedora, use:
árbol de instalación sudo dnf
En Manjaro, el comando es:
sudo pacman-Sy árbol
El uso de tree
sin parámetros dibuja el árbol debajo del directorio actual.
árbol
Puede pasar una ruta al tree
en la línea de comando.
trabajo de árbol
La opción -d
(directorios) excluye archivos y solo muestra directorios.
árbol -d trabajo
Esta es la forma más conveniente de obtener una vista clara de la estructura de un árbol de directorios. El árbol de directorios que se muestra aquí es el que se utiliza en los siguientes ejemplos. Hay cinco archivos de texto y ocho directorios.
No analice la salida de ls a directorios transversales
Su primer pensamiento podría ser, si ls
puede recorrer recursivamente un árbol de directorios, ¿por qué no usar ls
para hacer precisamente eso y canalizar la salida a otros comandos que analizan los directorios y realizan algunas acciones?
Analizar la salida de ls
se considera una mala práctica. Debido a la capacidad de Linux para crear nombres de archivos y directorios que contengan todo tipo de caracteres extraños, se vuelve muy difícil crear un analizador genérico universalmente correcto.
Es posible que nunca cree a sabiendas un nombre de directorio tan absurdo como este, pero un error en una secuencia de comandos o una aplicación podría hacerlo.
El análisis de nombres de archivos y directorios legítimos pero mal considerados es propenso a errores. Hay otros métodos que podemos usar que son más seguros y mucho más robustos que confiar en la interpretación de la salida de ls
.
Usando el comando de búsqueda
El comando de find
tiene capacidades recursivas incorporadas y también tiene la capacidad de ejecutar comandos por nosotros. Esto nos permite construir poderosas frases ingeniosas. Si es algo que probablemente quiera usar en el futuro, puede convertir su frase de una sola línea en un alias o una función de shell.
Este comando recorre recursivamente el árbol de directorios, buscando directorios. Cada vez que encuentra un directorio, imprime el nombre del directorio y repite la búsqueda dentro de ese directorio. Habiendo completado la búsqueda en un directorio, sale de ese directorio y reanuda la búsqueda en su directorio principal.
encontrar trabajo -type d -execdir echo "In:" {} \;
Puede ver por el orden en que se enumeran los directorios, cómo avanza la búsqueda a través del árbol. Al comparar la salida del comando de tree
con la salida de find
one-liner, verá cómo find
busca cada directorio y subdirectorio uno a uno hasta que llega a un directorio sin subdirectorios. Luego vuelve a subir un nivel y reanuda la búsqueda en ese nivel.
Así es como se compone el comando.
- find : El comando de
find
. - trabajo : El directorio para comenzar la búsqueda. Puede ser una ruta.
- -type d : Estamos buscando directorios.
- -execdir : Vamos a ejecutar un comando en cada directorio que encontremos.
- echo “In:” {} : Este es el comando. Simplemente hacemos eco del nombre del directorio en la ventana de la terminal. El "{}" contiene el nombre del directorio actual.
- \; : Este es un punto y coma que se usa para terminar el comando. Necesitamos escapar con la barra invertida para que Bash no lo interprete directamente.
Con un ligero cambio, podemos hacer que el comando de búsqueda devuelva archivos que coincidan con una pista de búsqueda. Necesitamos incluir la opción -name y una pista de búsqueda. En este ejemplo, buscamos archivos de texto que coincidan con "*.txt" y hacemos eco de su nombre en la ventana de la terminal.

encontrar trabajo -nombre "*.txt" -tipo f -execdir echo "Encontrado:" {} \;
Ya sea que busque archivos o directorios, depende de lo que quiera lograr. Para ejecutar un comando dentro de cada directorio , use -type d
. Para ejecutar un comando en cada archivo coincidente , use -type f
.
Este comando cuenta las líneas en todos los archivos de texto en el directorio y subdirectorios de inicio.
encontrar trabajo -nombre "*.txt" -tipo f -execdir wc -l {} \;
RELACIONADO: Cómo usar el comando de búsqueda en Linux
Recorriendo árboles de directorios con un script
Si necesita recorrer directorios dentro de una secuencia de comandos, puede usar el comando de find
dentro de su secuencia de comandos. Si necesita, o simplemente desea, realizar las búsquedas recursivas usted mismo, también puede hacerlo.
#!/bin/bash shopt -s dotglob nullglob función recursiva { local current_dir dir_or_file para current_dir en $1; hacer echo "Comando de directorio para:" $current_dir para dir_or_file en "$current_dir"/*; hacer if [[ -d $dir_or_file ]]; después recursivo "$dir_or_file" más wc $dir_or_file fi hecho hecho } recursivo "$1"
Copie el texto en un editor y guárdelo como "recurse.sh", luego use el comando chmod
para hacerlo ejecutable.
chmod +x recurse.sh
El script establece dos opciones de shell, dotglob
y nullglob
.
La configuración dotglob
significa nombres de archivos y directorios que comienzan con un punto “ .
” se devolverá cuando se expandan los términos de búsqueda con comodines. Esto significa que estamos incluyendo archivos y directorios ocultos en nuestros resultados de búsqueda.
La configuración nullglob
significa que los patrones de búsqueda que no encuentran ningún resultado se tratan como una cadena vacía o nula. No tienen como valor predeterminado el término de búsqueda en sí. En otras palabras, si estamos buscando todo en un directorio usando el comodín de asterisco “ *
”, pero no hay resultados, recibiremos una cadena nula en lugar de una cadena que contiene un asterisco. Esto evita que la secuencia de comandos intente abrir un directorio llamado "*" o trate "*" como un nombre de archivo.
A continuación, define una función llamada recursive
. Aquí es donde suceden las cosas interesantes.
Se declaran dos variables, llamadas current_dir
y dir_or_file
. Estas son variables locales, y solo pueden ser referenciadas dentro de la función.
Una variable llamada $1
también se usa dentro de la función. Este es el primer (y único) parámetro que se pasa a la función cuando se llama.
El script usa dos bucles for
, uno anidado dentro del otro. El primer bucle for
(externo) se usa para dos cosas.
Una es ejecutar cualquier comando que desee ejecutar en cada directorio. Todo lo que estamos haciendo aquí es hacer eco del nombre del directorio en la ventana de la terminal. Por supuesto, podría usar cualquier comando o secuencia de comandos, o llamar a otra función de script.
La segunda cosa que hace el bucle for externo es verificar todos los objetos del sistema de archivos que puede encontrar, que serán archivos o directorios. Este es el propósito del bucle for
interno. A su vez, cada nombre de archivo o directorio se pasa a la variable dir_or_file
.
La variable dir_or_file
luego se prueba en una declaración if para ver si es un directorio.
- Si es así, la función se llama a sí misma y pasa el nombre del directorio como parámetro.
- Si la variable
dir_or_file
no es un directorio, entonces debe ser un archivo. Cualquier comando que desee que se aplique al archivo se puede llamar desde la cláusulaelse
de la instrucciónif
. También puede llamar a otra función dentro del mismo script.
La línea final en el script llama a la función recursive
y pasa el primer parámetro de línea de comando $1
como el directorio de inicio para buscar. Esto es lo que inicia todo el proceso.
Ejecutemos el script.
./recurse.sh trabajo
Los directorios se recorren, y el punto en el script donde se ejecutaría un comando en cada directorio se indica mediante las líneas "Directorio comando para:". Los archivos que se encuentran tienen el comando wc
ejecutándose en ellos para contar líneas, palabras y caracteres.
El primer directorio procesado es "trabajo", seguido de cada rama de directorio anidado del árbol.
Un punto interesante a tener en cuenta es que puede cambiar el orden en que se procesan los directorios, moviendo los comandos específicos del directorio de estar encima del bucle for interno a estar debajo de él.
Vamos a mover la línea "Directorio de comando para:" después del done
del bucle for
interno.
#!/bin/bash shopt -s dotglob nullglob función recursiva { local current_dir dir_or_file para current_dir en $1; hacer para dir_or_file en "$current_dir"/*; hacer if [[ -d $dir_or_file ]]; después recursivo "$dir_or_file" más wc $dir_or_file fi hecho echo "Comando de directorio para:" $current_dir hecho } recursivo "$1"
Ahora ejecutaremos el script una vez más.
./recurse.sh trabajo
Esta vez, los directorios tienen los comandos aplicados primero desde los niveles más profundos, trabajando de regreso a las ramas del árbol. El directorio pasado como parámetro al script se procesa en último lugar.
Si es importante procesar primero los directorios más profundos, así es como puede hacerlo.
La recursividad es rara
Es como llamarte a ti mismo a tu propio teléfono y dejarte un mensaje para que te diga cuándo te verás la próxima vez, repetidamente.
Puede tomar un poco de esfuerzo antes de que capte sus beneficios, pero cuando lo haga, verá que es una forma programáticamente elegante de abordar problemas difíciles.
RELACIONADO: ¿Qué es la recursividad en la programación y cómo se usa?