¿Listando solo directorios usando ls en Bash?

955

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

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

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

Sibi
fuente
77
Vea la edición de esta respuesta unix.stackexchange.com/a/75047/32647 explicando lo que -drealmente significa.
Evgeni Sergeev

Respuestas:

993

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

Gordon Davisson
fuente
88
Tenga en cuenta que */no coincidirá con ninguna carpeta oculta. Para incluirlos, especifíquelos explícitamente como ls -d .*/ */, o configure la dotglobopción en Bash.
Gergő
1
@ytpillai Eso sucede porque no hay subdirectorios para enumerar. Obtiene ese error cada vez que usa lsalgo que no existe.
Gordon Davisson
1
Muy bien, gracias, lo comprobé hace un momento y resulta que el único directorio es la carpeta raíz.
ytpillai 01 de
1
@GordonDavisson El mensaje de falla podría evitarse con la opción bashshopt -s nullglob
44
@BinaryZebra Establecer nullglob evitaría el mensaje de error, pero causaría aún más confusión: con nullglob configurado y sin subdirectorios, ls */se expandiría a solo ls, lo que enumeraría todos los archivos en el directorio actual. Estoy bastante seguro de que eso no es lo que quieres en ese caso.
Gordon Davisson
481

Cuatro formas de hacer esto, cada una con un formato de salida diferente

1. Usando echo

Ejemplo: echo */, echo */*/
Aquí es lo que tengo:

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

2. Usando lssolo

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

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

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

3. Usando lsygrep

Ejemplo: esto ls -l | grep "^d" 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 recomendado para nombres de archivo que contienen espacios)

Ejemplo: esto for i in $(ls -d */); do echo ${i%%/}; done
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

cs/  
draft/  
files/  
hacks/  
masters/  
static/
Albert
fuente
2
NÓTESE BIEN. 3fue notablemente más lento que los demás para mí. En el directorio que probé: 1.012s, 2.016s, 3 .055s , 4.021s.
isomorphismes
@isomorphismes, ¿cómo midiste el tiempo? ¿Por qué medios? Por cierto, tengo que decir que No. 1es mi favorito.
Albert
Albert, solía time, la función Unix. /// Estoy de acuerdo, echo */es más inteligente que ls -d */.
isomorfismos el
99
Dos cosas menores que debes tener en cuenta. ls -l | grep "^ d" filtra los enlaces simbólicos a los directorios, mientras que 'ls -d * /' los muestra. Además, 'ls -d * /' falla si no hay directorios presentes en el directorio de destino.
Zoran Pavlovic
15
La 1.opción causará grandes dolores al tratar con nombres de carpetas que tienen espacios.
Shrikant Sharat
99

Yo suelo:

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

Esto crea una sola columna sin barra diagonal - útil en scripts.

Mis dos centavos.

Thomas Altfather Bueno
fuente
18
La -1opción para lssaldrá también en formato de columna única, como en ls -1 -d */.
Kalin
3
@ user29020 Debe tener en cuenta que -1aún genera una barra diagonal final para cada entrada.
Dennis
Cuando agrego esto .bashrccomo alias, ¿cómo agrego '/'?
ARN
@RNA tarde para responder, pero para las personas futuras: ¿intenta escapar con una barra invertida? '\/'
Caek
1
Se rompe si hay una barra diagonal. Esto elimina solo las barras diagonales:| sed -e 's-/$--'
Victor Sergienko el
62

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
at3m
fuente
2
Para coincidir con la pregunta (pero incluir archivos de puntos), el primero debe ser: de lo find /home/alice/Documents -maxdepth 1 -mindepth 1 -type dcontrario, se incluye a /home/alice/Documentssí mismo. Para incluir enlaces simbólicos a directorios, prefijo con-L
jhnc
Esta parece ser la solución más sensata, ya que find es la herramienta que realmente está hecha para esta tarea. Puede excluir el primer resultado - ./ para el directorio actual - canalizando a grep -v '^ \ ./$'
siliconrockstar el
38

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 archivo que coinciden con el patrón.
Un asterisco simple coincidirá con todos los nombres de archivo en el PWD (directorio de trabajo actual).
Un patrón más complejo */que coincidirá con todos los nombres de archivo que terminan en /.
Por lo tanto, todos los directorios. Por eso el comando:

1.- eco.

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

se expandirá (por el shell) a echotodos los directorios en el PWD.


Para probar esto: Cree un directorio ( mkdir) llamado como test-dir, y cden é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 nombres impares:

./--/ ./-/ ./*/ ./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 echousar ls, el shell sigue siendo lo que está expandiendo la lista de nombres de archivo. El shell es la razón para obtener una lista de directorios en el PWD. La -dopción para lshacer que enumere la entrada del directorio actual 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 nombres impares enumerados anteriormente. Se ahogará con varios nombres. Necesita borrar uno por uno hasta que encuentre los que tengan problemas.

2.- ls

La GNU lsaceptará la --tecla "fin de 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 intento como este:

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

Fallará en:

  • algunos nombres ( ls -d */) como ya se muestra arriba.
  • se verá afectado por el valor de IFS.
  • dividirá los nombres en espacios y pestañas (por defecto IFS).
  • cada nueva línea en el nombre comenzará un nuevo comando echo.

4.- Función

Finalmente, el uso de la lista de argumentos dentro de una función no afectará la lista de argumentos del actual shell en ejecución. 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 extraños.


fuente
Creo que deberías reemplazar la palabra Seguro por Confiable. Su publicación me hace pensar que las otras soluciones son 'inseguras' (vulnerables o explotables).
Amado Martínez
1
@AmadoMartinez Hecho un general s / seguro / confiable /. ¿Mejor?
21

El treecomando 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 desea 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 -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 man tree

Hamish Downer
fuente
15

En caso de que se pregunte por qué la salida de 'ls -d * /' le proporciona dos barras diagonales finales, como:

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

Probablemente se deba a que en algún lugar sus archivos de configuración de shell o sesión alias el comando ls a una versión de ls que incluye el indicador -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. Entonces, una barra oblicua coincide con el patrón '* /', y la otra barra oblicua es el indicador de tipo adjunto.

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

\ ls -d * /

gwideman
fuente
11

Solo agrego esto a mi .bashrcarchivo (también puede escribirlo en la línea de comando si solo lo necesita / desea para una sesión)

alias lsd='ls -ld */'

entonces lsd producirá el resultado deseado.

adivinadores
fuente
¿No podrías usarlo? ls -l ruta | grep dr
jrobertsz66
55
"entonces lsd producirá el resultado deseado". Me río
fbafelipe
1
En mi experiencia, produce un resultado.
Todd
Yo uso 'lad' (listar todos los directorios), y también incluí '. * /' Para incluir directorios ocultos también. Por supuesto, la insinuación tampoco se me ha perdido.
DryLabRebel
11

lsSolución 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 del subdirectorio. Una lssolución verdadera es útil, ya que permite el uso de lsopciones para ordenar el orden, etc.

Excluyendo enlaces simbólicos

Se lsha dado una solución usando , pero hace algo diferente de las otras soluciones, ya que excluye enlaces simbólicos a directorios:

ls -l | grep '^d'

(posiblemente canalizando sedo awkpara aislar los nombres de archivo)

Incluyendo enlaces simbólicos

En el caso (probablemente más común) de que se deben incluir enlaces simbólicos a directorios, podemos usar la -popción de ls, lo que hace que agregue un carácter de barra diagonal a los nombres de directorios (incluidos los enlaces simbólicos):

ls -1p | grep '/$'

o, deshacerse de las barras diagonales finales:

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

Podemos agregar opciones lssegún sea necesario (si se usa una lista larga, -1ya no es necesaria).

nota: si queremos barras diagonales finales, pero no queremos que se destaquen grep, podemos eliminar el resaltado hackeando la parte correspondiente de la línea vacía:

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

Si no es necesario incluir el directorio oculto, ofrezco:

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

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

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

O

find -maxdepth 1 -type d | awk -F"./" '{print $2}'
PHP Learner
fuente
Si necesita saber más sobre esto awk, mire esta respuesta
PHP Learner
En comparación con otras respuestas, la primera opción de "ls .. | grep ... | awk" parece excesiva secuencia de comandos.
Lars Nordin
1
Asume que ningún directorio tiene espacios en blanco dentro de sus nombres.
Benjamin R
7

para mostrar listas de carpetas sin /

ls -d */|sed 's|[/]||g'
wholanda
fuente
2
ols -d1 */ | tr -d "/"
ccpizza
No es necesario llamar a un comando externo:set -- */; printf "%s\n" "${@%/}"
Me gusta la solución de @wholanda. Mi solución un poco más corta es (probada y funciona): ls -d * / | sed 's | / || g'
klor
También es útil tener un alias lsdir: alias lsdirs = "ls -d * / | sed 's | / || g'"
klor
6

Esto es lo que estoy usando

ls -d1 /Directory/Path/*;

Prohibición
fuente
Esta es realmente una buena solución para mostrarla línea por línea.
Nikolay Frick
No solo incluirá directorios. Debe agregar una barra diagonal:ls -d1 /Directory/Path/*/
Skippy le Grand Gourou
6

Para listar solo directorios :

ls -l | grep ^d

para listar solo archivos :

ls -l | grep -v ^d 

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

Vijay Gawas
fuente
4

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

for i in $(ls); do test -d $i && echo $i ; done
nmarques
fuente
1
Explique qué hace este código y cómo se relaciona con la pregunta.
Ken YN
1
ejecuta el comando 'ls' y luego recorre la salida probando si cada uno es un directorio y
repitiendo
3

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

Para enumerar directorios solamente, 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 -d a* # limit to directories beginning with letter 'a'
llod -d .* # limit to hidden directories

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

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

Para su información, si desea imprimir todos los archivos en varias líneas, puede hacer uno ls -1que imprima cada archivo en una línea separada. archivo1 archivo2 archivo3

warfreak92
fuente
3

Una lista simple del directorio actual, sería:

ls -1d ./*/

¿Lo quieres ordenado y limpio?

ls -1d ./*/ | cut -c 3- | rev | cut -c 2- | rev | sort

Recuerde: los caracteres en mayúscula tienen un comportamiento diferente en el orden

PYK
fuente
3

Prueba este. Funciona para todas las distribuciones de Linux.

ls -ltr | grep drw
Raj RD
fuente
44
ls -l | grep '^d' | awk '{print $9}'
dw1
2

One-liner para listar directorios solo desde "aquí".

Con recuento de archivos.

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

Paré 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 mayor :)

inukaze
fuente
2

Agregando 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ía ser bastante útil.

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/
BilliAm
fuente
2

Usando Perl:

ls | perl -nle 'print if -d;'
Paul-Gerhard Woolcock
fuente
1

Esto es lo que uso para enumerar solo los nombres de directorio:

ls -1d /some/folder/*/ | awk -F "/" "{print \$(NF-1)}"
Robert Lujo
fuente
1

Para responder a la pregunta original, */no tiene nada que ver con lsper se; se realiza mediante el shell / Bash, en un proceso conocido como globbing .

Esta es la razón echo */y la ls -d */salida de los mismos elementos. (El -dindicador hace que se lsmuestren los nombres de directorio y no el contenido de los directorios).

flow2k
fuente
1

Aquí hay una variación usando el árbol que genera nombres de directorio solo en líneas separadas, sí, es feo pero bueno, funciona.

tree -d | grep -E '^[├|└]' | cut -d ' ' -f2

o con awk

tree -d | grep -E '^[├|└]' | awk '{print $2}'

Sin embargo, esto probablemente sea mejor y retendrá el /nombre del directorio posterior.

ls -l | grep "^d" | awk '{print $9}'
lacostenycoder
fuente
esto se parece a coreano!
Paschalis
0
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 se puede refinar 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
AVS
fuente
0

El comando más corto de todos los tiempos (en realidad, un truco) para listar solo directorios. Escriba la ruta absoluta o la ruta relativa del directorio de interés y presione enter para ingresar al directorio de interés. Ahora escriba cdy presione la tecla Tab . Solo se muestran los directorios ahora.

user@ubuntu:~/Desktop$cd <tab key>

El comando anterior ahora debería mostrar solo las carpetas en el escritorio . Más corto de hecho.

Prometeo
fuente
Esto supone que el autocompletado está habilitado y puede no funcionar en todos los casos. Además, si desea hacer algo con esto, como canalizar la salida en algo, no funcionará. Pero solo por ver la salida, seguro que funciona de manera rápida y fácil.
lacostenycoder
¡Perfecto! Eliminé el "." Y luego funcionó
user2060451