Elencare solo le directory usando ls in Bash?


954

Questo comando elenca le directory nel percorso corrente: ls -d */

Cosa fa esattamente il modello */?

E come possiamo dare il percorso assoluto nel comando sopra (es. ls -d /home/alice/Documents) Per elencare solo le directory in quel percorso?


7
Vedi la modifica a questa risposta unix.stackexchange.com/a/75047/32647 che spiega cosa -dsignifica effettivamente.
Evgeni Sergeev,

Risposte:


992

*/è un modello che corrisponde a tutte le sottodirectory nella directory corrente ( *corrisponderebbe a tutti i file e le sottodirectory; lo /limita alle directory). Allo stesso modo, per elencare tutte le sottodirectory in / home / alice / Documents, usarels -d /home/alice/Documents/*/


88
Nota che */non corrisponderà a nessuna cartella nascosta. Per includerli, specificali in modo esplicito ls -d .*/ */o imposta l' dotglobopzione in Bash.
Gergő,

1
@ytpillai Succede perché non ci sono sottodirectory da elencare. Ricevi questo errore ogni volta che lo usi lssu qualcosa che non esiste.
Gordon Davisson

1
Va bene grazie, l'ho verificato proprio ora e si scopre che l'unica directory è la cartella principale.
ytpillai,

1
@GordonDavisson Il messaggio di errore potrebbe essere evitato con l'opzione bashshopt -s nullglob

4
@BinaryZebra L'impostazione di nullglob eviterebbe il messaggio di errore, ma causerebbe ancora più confusione: con nullglob impostato e nessuna sottodirectory, ls */si espanderebbe a just ls, che elencherebbe tutti i file nella directory corrente. Sono abbastanza sicuro che non è quello che vuoi in quel caso.
Gordon Davisson,

481

Quattro modi per farlo, ognuno con un formato di output diverso

1. Utilizzo echo

Esempio: echo */,echo */*/
Ecco cosa ho ottenuto:

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

2. lsSolo usando

Esempio: ls -d */
ecco esattamente quello che ho ottenuto:

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

O come elenco (con informazioni dettagliate): ls -dl */

3. Utilizzo ls egrep

Esempio: ls -l | grep "^d" ecco cosa ho ottenuto:

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 (non consigliato per il nome file contenente spazi)

Esempio: for i in $(ls -d */); do echo ${i%%/}; done
ecco cosa ho ottenuto:

cs  
draft  
files  
hacks  
masters  
static

Se ti piace avere '/' come carattere finale, il comando sarà: for i in $(ls -d */); do echo ${i}; done

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

2
NB. 3per me è stato notevolmente più lento degli altri. Nella directory che ho testato: 1.012s, 2.016s, 3 .055s , 4.021s.
isomorfismi

@isomorfismi, come hai misurato il tempo? Con quali mezzi? A proposito, devo dire, No. 1è il mio preferito.
Albert,

Albert, ho usato timela funzione Unix. /// Sono d'accordo, echo */è più intelligente di ls -d */.
isomorfismi

9
Due cose minori che dovresti notare. ls -l | grep "^ d" filtra i collegamenti simbolici alle directory, mentre "ls -d * /" li visualizza. Inoltre, 'ls -d * /' ha esito negativo se non ci sono directory presenti nella directory di destinazione.
Zoran Pavlovic,

15
L' 1.opzione causerà gravi problemi quando si ha a che fare con nomi di cartelle che hanno spazi.
Shrikant Sharat,

99

Io uso:

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

Questo crea una singola colonna senza barra rovesciata, utile negli script.

I miei due centesimi.


18
L' -1opzione per lsverrà prodotta anche in formato a colonna singola, così come in ls -1 -d */.
Kalin,

3
@ user29020 Va notato che -1genera comunque una barra finale per ogni voce.
Dennis,

Quando lo aggiungo .bashrccome alias, come aggiungo '/'?
RNA

@RNA in ritardo per rispondere, ma per le persone future: provare a fuggire con una barra rovesciata? '\/'
Caek

1
Si rompe se c'è una barra iniziale. Questo rimuove solo le barre finali:| sed -e 's-/$--'
Victor Sergienko,

62

Per tutte le cartelle senza sottocartelle:

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

Per tutte le cartelle con sottocartelle:

find /home/alice/Documents -type d

2
Per abbinare la domanda (ma includere dotfile), il primo dovrebbe essere: find /home/alice/Documents -maxdepth 1 -mindepth 1 -type daltrimenti includi /home/alice/Documentsse stesso. Per includere collegamenti simbolici alle directory, -L
aggiungere il

Queste sembrano le soluzioni più sanitarie, poiché find è lo strumento che è stato creato per questo compito. Puoi escludere il primo risultato - ./ per la directory corrente - eseguendo il piping su grep -v '^ \ ./$'
siliconrockstar

38

4 (più) Opzioni affidabili.

Un asterisco non quotato* verrà interpretato come un pattern (glob) dalla shell.
La shell lo utilizzerà nell'espansione del nome percorso.
Genererà quindi un elenco di nomi di file che corrispondono al modello.
Un semplice asterisco corrisponderà a tutti i nomi di file nel PWD (presente directory di lavoro).
Un modello più complesso in quanto */corrisponderà a tutti i nomi di file che finiscono in /.
Quindi, tutte le directory. Ecco perché il comando:

1.- eco.

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

verrà espanso (dalla shell) in echotutte le directory nel PWD.


Per provare questo: crea una directory ( mkdir) chiamata come test-dir, e cdin essa:

mkdir test-dir; cd test-dir

Crea alcune directory:

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:

Il comando echo ./*/rimarrà affidabile anche con file con nomi dispari:

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

Ma gli spazi nei nomi dei file rendono la lettura un po 'confusa.


Se invece di echo, usiamo ls, la shell è ancora ciò che sta espandendo l'elenco dei nomi dei file. La shell è il motivo per ottenere un elenco di directory nel PWD. L' -dopzione per lsrenderlo elencare la voce della directory attuale invece del contenuto di ciascuna directory (come presentato per impostazione predefinita).

ls -d */

Tuttavia, questo comando è (in qualche modo) meno affidabile. Non funzionerà con i file con nomi dispari elencati sopra. Si strozzerà con diversi nomi. Devi cancellare uno per uno finché non trovi quelli con problemi.

2.- ls

La GNU lsaccetterà il --tasto "end of options" ( ).

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

3.-printf

Per elencare ogni directory nella sua riga (in una colonna, simile a ls -1), usare:

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

E, ancora meglio, potremmo rimuovere il finale /:

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

Un tentativo come questo:

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

Fallirà su:

  • alcuni nomi ( ls -d */) come già mostrato sopra.
  • sarà influenzato dal valore di IFS.
  • dividerà i nomi su spazi e schede (con impostazione predefinita IFS).
  • ogni nuova riga nel nome avvierà un nuovo comando echo.

4.- Funzione

Infine, l'utilizzo dell'elenco degli argomenti all'interno di una funzione non influirà sull'elenco degli argomenti della shell corrente in esecuzione. Semplicemente:

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

presenta questo elenco:

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

Queste opzioni sono sicure con diversi tipi di nomi di file dispari.


Penso che dovresti sostituire la parola Sicuro con Affidabile. Il tuo post mi fa pensare che le altre soluzioni siano "non sicure" (vulnerabili o sfruttabili)
Amado Martinez,

1
@AmadoMartinez Fatto un s generale / sicuro / affidabile /. Meglio?

21

Anche il treecomando è abbastanza utile qui. Di default mostrerà tutti i file e le directory a una profondità completa, con alcuni caratteri ASCII che mostrano l'albero delle directory.

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

Ma se volessimo ottenere solo le directory, senza l'albero ASCII, e con il percorso completo dalla directory corrente, potresti fare:

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

Gli argomenti sono:

-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 vuoi quindi il percorso assoluto, puoi iniziare specificando il percorso completo della directory corrente:

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

E per limitare il numero di sottodirectory, è possibile impostare il livello massimo di sottodirectory con -L level, ad esempio:

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

Ulteriori argomenti possono essere visti con man tree


15

Nel caso ti stai chiedendo perché l'output di 'ls -d * /' ti dia due barre finali, come:

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

è probabilmente perché da qualche parte la shell o la sessione configura i file alias il comando ls su una versione di ls che include il flag -F. Quel flag aggiunge un carattere a ciascun nome di output (che non è un semplice file) che indica il tipo di cosa. Quindi una barra corrisponde alla corrispondenza del modello '* /' e l'altra barra è l'indicatore del tipo allegato.

Per sbarazzarsi di questo problema, è possibile ovviamente definire un alias diverso per ls. Tuttavia, per non richiamare temporaneamente l'alias, è possibile anteporre il comando con la barra rovesciata:

\ ls -d * /


11

Ho appena aggiunto questo al mio .bashrcfile (potresti anche semplicemente digitarlo sulla riga di comando se ne hai bisogno / desideri solo per una sessione)

alias lsd='ls -ld */'

quindi lsd produrrà il risultato desiderato.


Non potresti semplicemente usare? percorso ls -l | grep dr
jrobertsz66,

5
"allora lsd produrrà il risultato desiderato." Rido
fbafelipe il

1
Nella mia esperienza, produce un risultato.
Todd,

Uso "lad" (elenca tutte le directory) e ho incluso anche ". * /" Per includere anche le directory nascoste. Certo, anche l'innuendo non si perde su di me.
DryLabRebel,

11

lsSoluzione effettiva , inclusi collegamenti simbolici alle directory

Molte risposte qui in realtà non lo usano ls(o lo usano solo in senso banale ls -d, mentre si usano i caratteri jolly per l'effettiva corrispondenza della sottodirectory. Una vera lssoluzione è utile, poiché consente l'uso di lsopzioni per l'ordinamento, ecc.

Esclusi i collegamenti simbolici

È lsstata fornita una soluzione che utilizza , ma fa qualcosa di diverso dalle altre soluzioni in quanto esclude i collegamenti simbolici alle directory:

ls -l | grep '^d'

(possibilmente eseguendo il piping attraverso sedo awkper isolare i nomi dei file)

Compresi i collegamenti simbolici

Nel caso (probabilmente più comune) che dovrebbero essere inclusi collegamenti simbolici alle directory, possiamo usare l' -popzione di ls, che lo rende un carattere barra ai nomi delle directory (inclusi quelli con link simbolici):

ls -1p | grep '/$'

o, sbarazzarsi delle barre finali:

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

Siamo in grado di aggiungere opzioni a lsseconda delle necessità (se viene utilizzato un elenco lungo, -1non è più necessario).

nota: se vogliamo barre finali, ma non vogliamo grepche vengano evidenziate da , possiamo rimuovere in modo incisivo l'evidenziazione rendendo vuota la parte effettiva della riga corrispondente:

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

9

Se non è necessario elencare la directory nascosta, offro:

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

E se è necessario elencare le directory nascoste, utilizzare:

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

O

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

Se hai bisogno di saperne di più awk, consulta questa risposta
PHP Learner,

Rispetto ad altre risposte, la prima opzione di "ls .. | grep ... | awk" sembra uno scripting eccessivo.
Lars Nordin,

1
Supponi che nessuna directory abbia spazi bianchi all'interno dei loro nomi.
Benjamin R,

7

per mostrare gli elenchi di cartelle senza /

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

2
oppurels -d1 */ | tr -d "/"
ccpizza,

Non è necessario chiamare un comando esterno:set -- */; printf "%s\n" "${@%/}"

Mi piace la soluzione di @wholanda. La mia soluzione un po 'più breve è (testata e funzionante): ls -d * / | sed' s | / || g '
klor,

Anche avere un alias lsdir è utile: alias lsdirs = "ls -d * / | sed 's | / || g'"
klor,

6

Ecco cosa sto usando

ls -d1 /Directory/Path/*;


Questa è in realtà una buona soluzione per visualizzarla riga per riga.
Nikolay Frick,

Non elencherà solo le directory. È necessario aggiungere una barra finale:ls -d1 /Directory/Path/*/
Skippy le Grand Gourou,

6

Per elencare solo le directory :

ls -l | grep ^d

per elencare solo i file :

ls -l | grep -v ^d 

oppure puoi anche fare come: ls -ld * /


4

Verifica se l'elemento è una directory con test -d:

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

1
Spiegare cosa fa questo codice e come si collega alla domanda.
Ken YN,

1
esegue il comando 'ls' quindi scorre attraverso il test di output se ognuno è una directory e riecheggia se lo è ... funziona ma ci sono modi migliori
ShoeLace,

3

*/ è un modello di corrispondenza del nome file che corrisponde alle directory nella directory corrente.

Per elencare solo le directory, mi piace questa funzione:

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

Mettilo nel tuo .bashrc.

Esempi di utilizzo:

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: si romperà se si utilizza l' -iopzione. Ecco una soluzione per questo:

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

3

Cordiali saluti, se si desidera stampare tutti i file su più righe, è possibile eseguire una operazione ls -1che stamperà ogni file in una riga separata. file1 file2 file3


3

Un semplice elenco della directory corrente, sarebbe:

ls -1d ./*/

Lo vuoi ordinato e pulito?

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

Ricorda: i caratteri in maiuscolo hanno un comportamento diverso nell'ordinamento


3

Prova questo. Funziona con tutte le distribuzioni di Linux.

ls -ltr | grep drw

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

2

One-liner per elencare le directory solo da "qui".

Con il conteggio dei file.

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

2

Ho parzialmente risolto 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

Bene, questo mi riduce, la parte del sindaco :)


2

Aggiungendo per rendere il cerchio completo, per recuperare il percorso di ogni cartella, utilizzare una combinazione della risposta di Albert e di Gordan che dovrebbe essere piuttosto utile.

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

Produzione:

/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

Ecco cosa uso per elencare solo i nomi delle directory:

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

1

Per rispondere alla domanda originale, */non ha nulla a che fare con di lsper sé; è fatto dalla shell / Bash, in un processo noto come globbing .

Questo è il motivo echo */e l' ls -d */output degli stessi elementi. (Il -dflag rende in lsoutput i nomi delle directory e non i contenuti delle directory.)


1

Ecco una variante che utilizza l'albero che genera nomi di directory solo su linee separate, sì, è brutto ma, ehi, funziona.

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

o con awk

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

Questo è probabilmente meglio e manterrà il /nome della directory after.

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

questo sembra coreano!
Paschalis,

0
file *|grep directory

O / P (Sulla mia macchina) -

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

L'output sopra può essere perfezionato più usando il taglio.

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

Il comando più breve di sempre (in realtà un hack) per elencare solo le directory. Digita il percorso assoluto o il percorso relativo della directory di interesse e premi invio per accedere alla directory di interesse. Ora digita cde premi il tasto tab . Ora vengono visualizzate solo le directory.

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

Il comando sopra dovrebbe ora visualizzare solo le cartelle sul desktop . Di certo il più corto.


Ciò presuppone che il completamento automatico sia abilitato e potrebbe non funzionare in tutti i casi. Inoltre, se volessi fare qualcosa con questo tipo di pipe l'output in qualcosa, non funzionerà. Ma per vedere solo l'output, è sicuro che funzioni velocemente e facilmente.
lacostenycoder,

Perfetto! Ho rimosso il "." E poi ha funzionato
user2060451
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.