Listado de directorios usando ls en bash: un examen

Este comando enumera directorios en la ruta actual: ls -d */

¿Qué hace exactamente el patrón */ do?

¿Y cómo podemos dar la ruta absoluta en el comando anterior (por ejemplo, ls -d /home/alice/Documents ) para listar solo directorios en esa ruta?

*/ es un patrón que coincide con todos los subdirectorios en el directorio actual ( * coincidiría con todos los archivos y subdirectorios, el / restringe a los directorios). Del mismo modo, para enumerar todos los subdirectorios en / home / alice / Documents, use ls -d /home/alice/Documents/*/

Cuatro formas de hacerlo, cada una con un formato de salida diferente

1. Usando echo

Ejemplo: echo */ , echo */*/
Esto es lo que obtuve:

 cs/ draft/ files/ hacks/ masters/ static/ cs/code/ files/images/ static/images/ static/stylesheets/ 

2. Usando ls solo

Ejemplo: ls -d */
Aquí es exactamente lo que obtuve:

 cs/ files/ masters/ draft/ hacks/ static/ 

O como lista (con información detallada): ls -dl */

3. Usando ls y grep

Ejemplo: ls -l | grep "^d" ls -l | grep "^d" Esto es lo que obtuve:

 drwxr-xr-x 24 h staff 816 Jun 8 10:55 cs drwxr-xr-x 6 h staff 204 Jun 8 10:55 draft drwxr-xr-x 9 h staff 306 Jun 8 10:55 files drwxr-xr-x 2 h staff 68 Jun 9 13:19 hacks drwxr-xr-x 6 h staff 204 Jun 8 10:55 masters drwxr-xr-x 4 h staff 136 Jun 8 10:55 static 

4. Bash Script (No se recomienda para el nombre de archivo contener espacio).

Ejemplo: for i in $(ls -d */); do echo ${i%%/}; done for i in $(ls -d */); do echo ${i%%/}; done
Esto es lo que obtuve:

 cs draft files hacks masters static 

Si desea tener ‘/’ como carácter final, el comando será: for i in $(ls -d */); do echo ${i}; done for i in $(ls -d */); do echo ${i}; done

 cs/ draft/ files/ hacks/ masters/ static/ 

Yo suelo:

 ls -d */ | cut -f1 -d'/' 

Esto crea una sola columna sin barra posterior, útil en las secuencias de comandos.

Mis dos centavos.

Para todas las carpetas sin subcarpetas:

 find /home/alice/Documents -maxdepth 1 -type d 

Para todas las carpetas con subcarpetas:

 find /home/alice/Documents -type d 

4 (más) Opciones confiables.

Un asterisco * sin comillas será interpretado como un patrón (glob) por el shell.
El shell lo usará en la expansión del nombre de ruta.
Luego generará una lista de nombres de archivos que coinciden con el patrón.
Un asterisco simple coincidirá con todos los nombres de archivo en el PWD (presente directorio de trabajo).
Un patrón más complejo como */ coincidirá con todos los nombres de archivo que terminan en / .
Por lo tanto, todos los directorios. Es por eso que el comando:

1.- eco.

 echo */ echo ./*/ ### avoid misinterpreting filenames like "-e dir" 

se expandirá (por el shell) para hacer echo todos los directorios en el PWD.


Para probar esto: cree un directorio ( mkdir ) llamado como test-dir y cd en él:

 mkdir test-dir; cd test-dir 

Crea algunos directorios:

 mkdir {cs,files,masters,draft,static} # safe directories. mkdir {*,-,--,-v\ var,-h,-n,dir\ with\ spaces} # some a bit less secure. touch -- 'file with spaces' '-a' '-l' 'filename' # and some files: 

El comando echo ./*/ seguirá siendo confiable incluso con archivos con nombre impar:

 ./--/ ./-/ ./*/ ./cs/ ./dir with spaces/ ./draft/ ./files/ ./-h/ ./masters/ ./-n/ ./static/ ./-v var/ 

Pero los espacios en los nombres de archivo hacen que la lectura sea un poco confusa.


Si en lugar de echo , usamos ls , el shell sigue siendo lo que está expandiendo la lista de nombres de archivos. El shell es la razón para obtener una lista de directorios en el PWD. La opción -d a ls hace listar la entrada actual del directorio en lugar de los contenidos de cada directorio (como se presenta por defecto).

 ls -d */ 

Sin embargo, este comando es (algo) menos confiable. Fallará con los archivos con nombre impar enumerados arriba. Se ahogará con varios nombres. Tienes que borrar uno por uno hasta que encuentres a los que tienen problemas.

2.- ls

El GNU ls aceptará la tecla “fin de las opciones” ( -- ).

 ls -d ./*/ ### more reliable BSD ls ls -d -- */ ### more reliable GNU ls 

3.-printf

Para enumerar cada directorio en su propia línea (en una columna, similar a ls -1), use:

 $ printf "%s\n" */ ### Correct even with "-", spaces or newlines. 

Y, aún mejor, podríamos eliminar el final / :

 $ set -- */; printf "%s\n" "${@%/}" ### Correct with spaces and newlines. 

Un bash como este:

 $ for i in $(ls -d */); do echo ${i%%/}; done 

Fallará en:

  • algunos nombres ( ls -d */ ) como ya se mostró arriba.
  • se verá afectado por el valor de IFS .
  • dividirá nombres en espacios y tabs (con IFS predeterminado).
  • cada nueva línea en el nombre iniciará un nuevo comando de eco.

4.- Función

Finalmente, el uso de la lista de argumentos dentro de una función no afectará a la lista de argumentos del shell en ejecución actual. Simplemente:

 $ listdirs(){ set -- */; printf "%s\n" "${@%/}"; } $ listdirs 

presenta esta lista:

 -- - * cs dir with spaces draft files -h masters -n static -v var 

Estas opciones son seguras con varios tipos de nombres de archivo impares.

El comando de tree también es bastante útil aquí. De forma predeterminada, mostrará todos los archivos y directorios a una profundidad completa, con algunos caracteres ascii que muestran el árbol de directorios.

 $ tree . ├── config.dat ├── data │ ├── data1.bin │ ├── data2.inf │ └── sql | │ └── data3.sql ├── images │ ├── background.jpg │ ├── icon.gif │ └── logo.jpg ├── program.exe └── readme.txt 

Pero si quisiéramos obtener solo los directorios, sin el árbol ascii, y con la ruta completa desde el directorio actual, podría hacer:

 $ tree -dfi . ./data ./data/sql ./images 

Los argumentos son:

 -d List directories only. -f Prints the full path prefix for each file. -i Makes tree not print the indentation lines, useful when used in conjunction with the -f option. 

Y si luego quiere la ruta absoluta, puede comenzar especificando la ruta completa al directorio actual:

 $ tree -dfi "$(pwd)" /home/alice/Documents /home/alice/Documents/data /home/alice/Documents/data/sql /home/alice/Documents/images 

Y para limitar el número de subdirectorios, puede establecer el nivel máximo de subdirectorios con el -L level , por ejemplo:

 $ tree -dfi -L 1 "$(pwd)" /home/alice/Documents /home/alice/Documents/data /home/alice/Documents/images 

Se pueden ver más argumentos con el árbol del hombre

En caso de que se esté preguntando por qué la salida de ‘ls -d * /’ le da dos barras inclinadas, como:

 [prompt]$ ls -d */ app// cgi-bin// lib// pub// 

es probable que se deba a que en algún lugar los archivos de configuración de su shell o sesión alias tienen el comando ls en una versión de ls que incluye el distintivo -F. Esa bandera agrega un carácter a cada nombre de salida (que no es un archivo simple) que indica el tipo de cosa que es. De modo que una barra oblicua es la que coincide con el patrón ‘* /’, y la otra barra inclinada es el indicador de tipo adjunto.

Para deshacerte de este problema, por supuesto podrías definir un alias diferente para ls. Sin embargo, para no invocar temporalmente el alias, puede anteponer el comando con la barra diagonal inversa:

\ ls -d * /

Acabo de agregar esto a mi archivo .bashrc (también podría simplemente escribirlo en la línea de comandos si solo lo necesita / desea para una sesión)

 alias lsd='ls -ld */' 

entonces lsd producirá el resultado deseado.

Si el directorio oculto no es necesario para ser enumerado, ofrezco:

 ls -l | grep "^d" | awk -F" " '{print $9}' 

Y si se necesitan directorios ocultos para ser enumerados, use:

 ls -Al | grep "^d" | awk -F" " '{print $9}' 

O

 find -maxdepth 1 -type d | awk -F"./" '{print $2}' 

para mostrar listas de carpetas sin /

 ls -d */|sed 's|[/]||g' 

Esto es lo que estoy usando

ls -d1 /Directory/Path/*;

Solución ls real, incluidos enlaces simbólicos a directorios

Muchas respuestas aquí en realidad no usan ls (o solo lo usan en el sentido trivial de ls -d , mientras usan comodines para la coincidencia real de subdirectorios. Una verdadera solución de ls es útil, ya que permite el uso de opciones de ls para ordenar el orden , etc.

Excluyendo enlaces simbólicos

Se ha dado una solución que usa ls , pero hace algo diferente de las otras soluciones en que excluye enlaces simbólicos a directorios:

 ls -l | grep '^d' 

(posiblemente pasando por sed o awk para aislar los nombres de los archivos)

Incluyendo enlaces simbólicos

En el caso (probablemente más común) de que se incluyan enlaces simbólicos a directorios, podemos usar la opción -p de ls :

 ls -1p | grep '/$' 

o, deshacerse de las barras posteriores:

 ls -1p | grep '/$' | sed 's/\/$//' 

Podemos agregar opciones a ls según sea necesario (si se usa una lista larga, el -1 ya no es necesario).

Nota: si queremos barras diagonales posteriores, pero no queremos que sean resaltadas por grep , podemos eliminar el resaltado de forma fraudulenta haciendo que la parte correspondiente de la línea quede vacía:

 ls -1p | grep -P '(?=/$)' 

Pruebe si el elemento es un directorio con test -d :

 for i in $(ls); do test -d $i && echo $i ; done 

One-liner para listar directorios solo desde “aquí”.

Con el conteo de archivos.

 for i in `ls -d */`; do g=`find ./$i -type f -print| wc -l`; echo "Directory $i contains $g files."; done 

*/ es un patrón de coincidencia de nombre de archivo que coincide con los directorios en el directorio actual.

Para enumerar solo directorios, me gusta esta función:

 # long list only directories llod () { ls -l --color=always "$@" | grep --color=never '^d' } 

Ponlo en tu .bashrc.

Ejemplos de uso:

 llod # long listing of all directories in current directory llod -tr # same but in chronological order oldest first llod -da* # limit to directories beginning with letter 'a' llod -d .* # limit to hidden directories 

NOTA: se romperá si usa la opción -i . Aquí hay una solución para eso:

 # long list only directories llod () { ls -l --color=always "$@" | egrep --color=never '^d|^[[:digit:]]+ d' } 

FYI, si desea imprimir todos los archivos en varias líneas, puede hacer un ls -1 que imprimirá cada archivo en una línea separada. archivo1 archivo2 archivo3

Usando Perl:

 ls | perl -nle 'print if -d;' 

Lo resolví parcialmente con:

 cd "/path/to/pricipal/folder" for i in $(ls -d .*/); do sudo ln -s "$PWD"/${i%%/} /home/inukaze/${i%%/}; done ln: «/home/inukaze/./.»: can't overwrite a directory ln: «/home/inukaze/../..»: can't overwrite a directory ln: accesing to «/home/inukaze/.config»: too much symbolics links levels ln: accesing to «/home/inukaze/.disruptive»: too much symbolics links levels ln: accesing to «/home/inukaze/innovations»: too much symbolics links levels ln: accesing to «/home/inukaze/sarl»: too much symbolics links levels ln: accesing to «/home/inukaze/.e_old»: too much symbolics links levels ln: accesing to «/home/inukaze/.gnome2_private»: too much symbolics links levels ln: accesing to «/home/inukaze/.gvfs»: too much symbolics links levels ln: accesing to «/home/inukaze/.kde»: too much symbolics links levels ln: accesing to «/home/inukaze/.local»: too much symbolics links levels ln: accesing to «/home/inukaze/.xVideoServiceThief»: too much symbolics links levels 

Bueno, esto me reduce, la parte principal 🙂

Para completar el círculo, para recuperar la ruta de cada carpeta, use una combinación de la respuesta de Albert y Gordans que deberían ser muy útiles.

 for i in $(ls -d /pathto/parent/folder/*/); do echo ${i%%/}; done 

Salida:

 /pathto/parent/folder/childfolder1/ /pathto/parent/folder/childfolder2/ /pathto/parent/folder/childfolder3/ /pathto/parent/folder/childfolder4/ /pathto/parent/folder/childfolder5/ /pathto/parent/folder/childfolder6/ /pathto/parent/folder/childfolder7/ /pathto/parent/folder/childfolder8/ 

Prueba este. esto funcionará en todas las distribuciones ls -ltr | grep drw

Para enumerar solo directorios :

 ls -l | grep ^d 

para listar solo archivos :

 ls -l | grep -v ^d 

o también puedes hacer lo siguiente: ls -ld * /

 file *|grep directory 

O / P (en mi máquina) –

 [root@rhel6 ~]# file *|grep directory mongo-example-master: directory nostarch: directory scriptzz: directory splunk: directory testdir: directory 

La salida anterior puede refinarse más usando corte.

 file *|grep directory|cut -d':' -f1 mongo-example-master nostarch scriptzz splunk testdir * could be replaced with any path that's permitted file - determine file type grep - searches for string named directory -d - to specify a field delimiter -f1 - denotes field 1