Listando apenas diretórios usando ls no Bash?


954

Este comando lista os diretórios no caminho atual: ls -d */

O que exatamente o padrão */faz?

E como podemos fornecer o caminho absoluto no comando acima (por exemplo ls -d /home/alice/Documents) para listar apenas diretórios nesse caminho?


7
Veja a edição desta resposta unix.stackexchange.com/a/75047/32647, explicando o que -drealmente significa.
Evgeni Sergeev 12/08

Respostas:


992

*/é um padrão que corresponde a todos os subdiretórios no diretório atual ( *corresponderia a todos os arquivos e subdiretórios; o /restringe a diretórios). Da mesma forma, para listar todos os subdiretórios em / home / alice / Documents, usels -d /home/alice/Documents/*/


88
Observe que */não corresponderá a nenhuma pasta oculta. Para incluí-los, especifique-os explicitamente como ls -d .*/ */ou defina a dotglobopção no Bash.
Gergő 11/01

1
@ytpillai Isso está acontecendo porque não há subdiretórios para listar. Você recebe esse erro sempre que usa lsalgo que não existe.
Gordon Davisson

1
Tudo bem, obrigado, eu verifiquei isso agora e acontece que o único diretório é a pasta raiz.
Ytpillai

1
@GordonDavisson A mensagem de falha pode ser evitada com a opção bashshopt -s nullglob

4
@BinaryZebra Setting nullglob evitaria a mensagem de erro, mas causaria ainda mais confusão: com o nullglob set e sem subdiretórios, ls */seria expandido para apenas ls, o que listaria todos os arquivos no diretório atual. Tenho certeza de que não é o que você deseja nesse caso.
Gordon Davisson

481

Quatro maneiras de fazer isso, cada uma com um formato de saída diferente

1. Usando echo

Exemplo: echo */, echo */*/
Aqui está o que eu tenho:

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

2. Usando lsapenas

Exemplo: ls -d */
Aqui está exatamente o que eu recebi:

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

Ou como lista (com informações detalhadas): ls -dl */

3. Usando lsegrep

Exemplo: ls -l | grep "^d" Aqui está o que eu tenho:

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. Script Bash (não recomendado para nome de arquivo que contém espaços)

Exemplo: for i in $(ls -d */); do echo ${i%%/}; done
Aqui está o que eu tenho:

cs  
draft  
files  
hacks  
masters  
static

Se você gostaria de ter '/' como caractere final, o comando será: for i in $(ls -d */); do echo ${i}; done

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

2
NB 3foi visivelmente mais lento que os outros para mim. No diretório que testei: 1.012s, 2.016s, 3 .055s , 4.021s.
Isomorphismes

@isomorphismes, como você mediu o tempo? Pelo que significa? By the way, eu tenho que dizer, não. 1É o meu favorito.
Albert Albert

Albert, eu usei time, a função Unix. /// Eu concordo, echo */é mais esperto que ls -d */.
Isomorphismes

9
Duas pequenas coisas que você deve observar. ls -l | grep "^ d" filtra links simbólicos para diretórios, enquanto 'ls -d * /' os exibe. Além disso, 'ls -d * /' falha se não houver diretórios presentes no diretório de destino.
Zoran Pavlovic

15
A 1.opção causará grandes problemas ao lidar com nomes de pastas que possuem espaços.
Shrikant Sharat

99

Eu uso:

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

Isso cria uma única coluna sem barra à direita - útil em scripts.

Meus dois centavos.


18
A -1opção for também lsserá impressa em formato de coluna única, como em ls -1 -d */.
Kalin

3
@ user29020 Observe que -1ainda gera uma barra final para cada entrada.
Dennis

Quando adiciono isso .bashrccomo alias, como adiciono '/'?
RNA

@RNA atrasado para responder, mas para as pessoas do futuro: tente escapar com uma barra invertida? '\/'
Caek

1
Quebra se houver uma barra principal. Isso remove apenas as barras finais:| sed -e 's-/$--'
Victor Sergienko 23/10

62

Para todas as pastas sem subpastas:

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

Para todas as pastas com subpastas:

find /home/alice/Documents -type d

2
Para corresponder à pergunta (mas incluir arquivos de ponto), o primeiro deve ser: find /home/alice/Documents -maxdepth 1 -mindepth 1 -type dcaso contrário, você se inclui /home/alice/Documents. Para incluir links simbólicos para diretórios, prefixe com-L
jhnc 20/02/19

Essa parece ser a solução mais sadia, já que find é a ferramenta que realmente é feita para esta tarefa. Você pode excluir o primeiro resultado - ./ do diretório atual - canalizando para grep -v '^ \ ./$'
siliconrockstar

38

4 (mais) Opções confiáveis.

Um asterisco não citado* será interpretado como um padrão (glob) pelo shell.
O shell o utilizará na expansão do nome do caminho.
Ele irá gerar uma lista de nomes de arquivos que correspondem ao padrão.
Um asterisco simples corresponderá a todos os nomes de arquivos no PWD (atual diretório de trabalho).
Um padrão mais complexo, pois */corresponderá a todos os nomes de arquivos que terminam em /.
Assim, todos os diretórios. É por isso que o comando:

1.- eco.

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

será expandido (pelo shell) para echotodos os diretórios no PWD.


Para testar isso: Crie um diretório ( mkdir) chamado como test-dir e cdnele:

mkdir test-dir; cd test-dir

Crie alguns diretórios:

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:

O comando echo ./*/permanecerá confiável, mesmo com arquivos com nomes ímpares:

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

Mas os espaços nos nomes de arquivos tornam a leitura um pouco confusa.


Se em vez de echousarmos ls, o shell ainda é o que está expandindo a lista de nomes de arquivos. O shell é o motivo para obter uma lista de diretórios no PWD. A -dopção para lslistar a entrada atual do diretório em vez do conteúdo de cada diretório (como apresentado por padrão).

ls -d */

No entanto, este comando é (um pouco) menos confiável. Ele falhará com os arquivos nomeados ímpares listados acima. Vai sufocar com vários nomes. Você precisa apagar um por um até encontrar aqueles com problemas.

2.- ls

O GNU lsaceitará a --tecla "fim das opções" ( ).

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

3.-printf

Para listar cada diretório em sua própria linha (em uma coluna, semelhante a ls -1), use:

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

E, melhor ainda, podemos remover o final /:

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

Uma tentativa como esta:

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

Irá falhar:

  • alguns nomes ( ls -d */) como já mostrado acima.
  • será afetado pelo valor de IFS.
  • dividirá nomes em espaços e guias (com padrão IFS).
  • cada nova linha no nome iniciará um novo comando de eco.

4.- Função

Finalmente, o uso da lista de argumentos dentro de uma função não afetará a lista de argumentos do atual shell em execução. Simplesmente:

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

apresenta esta lista:

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

Essas opções são seguras com vários tipos de nomes de arquivos ímpares.


Eu acho que você deve substituir a palavra Seguro por Confiável. O envio da mensagem me faz pensar que as outras soluções são 'inseguros' (vulneráveis ou explorável.)
Amado Martinez

1
@AmadoMartinez Feito um s geral / seguro / confiável /. Melhor?

21

O treecomando também é bastante útil aqui. Por padrão, ele mostrará todos os arquivos e diretórios em uma profundidade completa, com alguns caracteres ascii mostrando a árvore de diretórios.

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

Mas se quisermos obter apenas os diretórios, sem a árvore ascii e com o caminho completo do diretório atual, você poderá:

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

Os argumentos são:

-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.

E se você quiser o caminho absoluto, poderá começar especificando o caminho completo para o diretório atual:

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

E para limitar o número de subdiretórios, você pode definir o nível máximo de subdiretórios com -L level, por exemplo:

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

Mais argumentos podem ser vistos com a árvore do homem


15

Caso você esteja se perguntando por que a saída de 'ls -d * /' fornece duas barras finais, como:

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

provavelmente é porque em algum lugar seus arquivos de configuração de shell ou sessão alias o comando ls para uma versão de ls que inclui o sinalizador -F. Esse sinalizador acrescenta um caractere a cada nome de saída (que não é um arquivo simples) indicando o tipo de coisa que é. Portanto, uma barra é a que corresponde ao padrão '* /' e a outra barra é o indicador de tipo anexado.

Para se livrar desse problema, é claro que você pode definir um alias diferente para ls. No entanto, para não invocar temporariamente o alias, você pode preceder o comando com barra invertida:

\ ls -d * /


11

Acabei de adicionar isso ao meu .bashrcarquivo (você também pode digitá-lo na linha de comando se precisar / desejar apenas para uma sessão)

alias lsd='ls -ld */'

então lsd produzirá o resultado desejado.


Você não poderia simplesmente usar? caminho ls -l | grep dr
jrobertsz66 /

5
"o lsd produzirá o resultado desejado." Eu ri
fbafelipe

1
Na minha experiência, produz um resultado.
Todd

Eu uso 'lad' (lista todos os diretórios) e também incluí '. * /' Para incluir diretórios ocultos também. Claro, a insinuação também não está perdida para mim.
DryLabRebel 5/19/19

11

lsSolução real , incluindo links simbólicos para diretórios

Muitas respostas aqui não são realmente usadas ls(ou apenas são usadas no sentido trivial de ls -d, enquanto se usam curingas para a correspondência de subdiretório real. Uma lssolução verdadeira é útil, pois permite o uso de lsopções para ordem de classificação, etc.

Excluindo links simbólicos

Uma solução lsfoi fornecida, mas faz algo diferente das outras soluções, na medida em que exclui links simbólicos para diretórios:

ls -l | grep '^d'

(possivelmente canalizando sedou awkisolando os nomes dos arquivos)

Incluindo links simbólicos

No caso (provavelmente mais comum) em que links simbólicos para diretórios devem ser incluídos, podemos usar a -popção de ls, o que o faz anexar um caractere de barra aos nomes dos diretórios (incluindo links simbólicos):

ls -1p | grep '/$'

ou, eliminando as barras finais:

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

Podemos adicionar opções lsconforme necessário (se uma lista longa for usada, ela -1não será mais necessária).

note: se queremos barras invertidas, mas não as destacamos grep, podemos removê-las de maneira hackeada, deixando vazia a parte correspondente da linha:

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

9

Se não for necessário listar o diretório oculto, ofereço:

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

E se for necessário listar diretórios ocultos, use:

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

OU

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

Se você precisa saber mais sobre awk, por favor, veja esta resposta
PHP Learner

Comparada a outras respostas, a primeira opção de "ls .. | grep ... | awk" parece um script excessivo.
Lars Nordin

1
Você está assumindo que nenhum diretório tem espaço em branco em seus nomes.
Benjamin R

7

para mostrar listas de pastas sem /

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

2
ouls -d1 */ | tr -d "/"
ccpizza 15/04

Não há necessidade de chamar um comando externo:set -- */; printf "%s\n" "${@%/}"

Eu gosto de solução de @wholanda. Minha um pouco mais curto solução é (testado e funciona): ls -d * / | sed 's | / || g'
klor

Também ter um alias lsdir é útil: lsdirs alias = "ls -d * / | sed 's | / g ||'"
klor

6

Aqui está o que eu estou usando

ls -d1 /Directory/Path/*;


Esta é realmente uma solução muito boa para exibi-la linha por linha.
Nikolay Frick

Não listará apenas diretórios. Você deve adicionar uma barra à direita:ls -d1 /Directory/Path/*/
Skippy le Grand Gourou

6

Para listar apenas diretórios :

ls -l | grep ^d

para listar apenas arquivos :

ls -l | grep -v ^d 

ou também você pode fazer como: ls -ld * /


4

Teste se o item é um diretório com test -d:

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

1
Por favor, explique o que esse código faz e como ele se relaciona com a pergunta.
Ken YN

1
ele é executado teh comando 'ls', em seguida, percorre a saída do teste-ing, se cada um é um diretório e eco-ing se é .. obras, mas há melhores maneiras
cadarço

3

*/ é um padrão de correspondência de nome de arquivo que corresponde aos diretórios no diretório atual.

Para listar apenas diretórios, eu gosto desta função:

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

Coloque-o no seu .bashrc.

Exemplos 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: ele será quebrado se você usar a -iopção. Aqui está uma correção para isso:

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

3

Para sua informação, se você quiser imprimir todos os arquivos em várias linhas, poderá fazer um ls -1para imprimir cada arquivo em uma linha separada. arquivo1 arquivo2 arquivo3


3

Uma lista simples do diretório atual, seria:

ls -1d ./*/

Deseja que ele seja limpo e organizado?

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

Lembre-se: caracteres em maiúsculas têm um comportamento diferente no tipo


3

Tente este. Funciona para todas as distribuições linux.

ls -ltr | grep drw

4
ls -l | grep '^d' | awk '{print $9}'
DW1

2

Uma linha para listar diretórios apenas a partir de "aqui".

Com contagem de arquivos.

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

2

Resolvi parcialmente com:

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

Bem, isso me reduz a parte do prefeito :)


2

Acrescentando para torná-lo um círculo completo, para recuperar o caminho de cada pasta, use uma combinação da resposta de Albert e de Gordans que devem ser bastante úteis.

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

Resultado:

/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/


1

Aqui está o que eu uso para listar apenas nomes de diretório:

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

1

Para responder à pergunta original, */nada tem a ver com isso ls; é feito pelo shell / Bash, em um processo conhecido como globbing .

É por isso que echo */e ls -d */produz os mesmos elementos. (O -dsinalizador lscria os nomes dos diretórios e não o conteúdo dos diretórios.)


1

Aqui está uma variação usando a árvore que gera nomes de diretório apenas em linhas separadas; sim, é feio, mas, ei, funciona.

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

ou com awk

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

Provavelmente, isso é melhor e manterá o /nome do diretório posterior.

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

isso parece coreano!
Paschalis

0
file *|grep directory

O / P (na minha máquina) -

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

A saída acima pode ser mais refinada usando o 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

0

O comando mais curto de todos os tempos (na verdade, um hack) para listar apenas diretórios. Digite o caminho absoluto ou o caminho relativo do diretório de interesse e pressione Enter para inserir o diretório de interesse. Agora digite cde pressione a tecla Tab . Somente os diretórios são mostrados agora.

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

O comando acima agora deve exibir apenas pastas na área de trabalho . Menor, de fato.


Isso pressupõe que o preenchimento automático está ativado e pode não funcionar em todos os casos. Além disso, se você quiser fazer algo com isso, como canalizar a saída para algo, não funcionará. Mas, apenas vendo a saída, com certeza funciona rápido e fácil.
lacostenycoder

Perfeito! Eu removi o "." E então funcionou #
2020451
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.