252

I want to list only the directories in specified path (ls doesn't have such option). Also, can this be done with a single line command?

neatnick
  • 1,489
  • 1
  • 18
  • 29
S'am
  • 2,521
  • 2
  • 15
  • 4
  • 15
    For the future: Maybe unix/linux basics type of questions not so hard related to programming are better keept there: http://unix.stackexchange.com/ – echox Sep 08 '10 at 11:54

23 Answers23

351

Try this ls -d */ to list directories within the current directory

David Hancock
  • 14,861
  • 4
  • 41
  • 44
  • 20
    Hey, that's pretty nifty, I always used to us `ls -al | grep '^d'` - this is much more succinct. – paxdiablo Sep 08 '10 at 11:48
  • 1
    This however gives e.g. `ls: */: No such file or directory` on `stderr` if there is no directory in the working directory. (Removed nonsense about `-d` before the other comments were posted). – Georg Fritzsche Sep 08 '10 at 12:07
  • No, the `-d` is not redundant. Without this parameter, `ls */` will show the contents of all directories in the current working directory. – joschi Sep 08 '10 at 12:07
  • That it does, I'm not sure if there is an easy way to overcome that. The -d is to prevent the directory contents being displayed. – David Hancock Sep 08 '10 at 12:07
  • 50
    why use */ ?? please explain!? – Rebooting Dec 04 '12 at 11:01
  • 8
    I don't have a proper explanation, however I do know that the `*/` forces the display of only items ending with a forward slash, which in this case would be a directory, even if the `-F` option of `ls` isn't used. Similar to the behaviour of `ls *php` and how it displays all files ending with `php` in a directory. – David Hancock Oct 18 '13 at 15:24
  • 3
    @user975234 Someone asked a similar question, and there's a pretty good explanation posted [link](http://superuser.com/questions/344877/ls-d-is-not-displaying-directories-is-there-a-way-to-get-ls-to-only-display-di) – user1766760 Dec 18 '13 at 22:06
  • 23
    Just `echo */` will do the same too – nos Apr 03 '14 at 21:19
  • 2
    Note that this solution depends on wildcard expansion, thus it might fail if there is a huge amount of subdirectories, giving a message "The parameter list is too long." I prefer @Robin's solution for "single responsibility". – peterp Apr 13 '14 at 08:55
  • this won't list directories starting with `.` – Kashyap Mar 14 '16 at 15:18
  • I still feel that `ls -d .` should be the "list all directories in the current directory" command. Thank you for this one, though! – marts Feb 24 '17 at 20:43
  • how do you then have the directories show in list format (so I can see the permissions) rather than pancaked all one-dimensionally? – Jerome Wiley Segovia Apr 07 '17 at 20:55
  • 1
    @JeromeWileySegovia ls -ld */ – Gabriel Hautclocq Aug 31 '17 at 08:40
  • 3
    If you use `ls -d {.*,*}/` it'll also list your hidden dotted folders. If that's what you want. – ocodo Jan 08 '18 at 03:31
  • @Chandeep For anyone wondering why */, this answer should clarify it: https://superuser.com/a/369960/1097408. In other words, `ls */` prints all directories with their content. Adding -d skips the latter. – SantaXL Oct 04 '19 at 23:02
  • @Chandeep - just to add to @SantaXL comment. `*` is just a regular expression syntax that matches 'anything'. So `ls -d */` will list literally 'anything' (except hidden files and directories) in the current directory. When followed by a forward slash `/` will list directories. – DryLabRebel Nov 22 '21 at 01:16
103

Try this:

find . -maxdepth 1 -type d
Robin
  • 4,242
  • 1
  • 20
  • 20
  • 11
    To me this looks to be the way it should be done. Unlike the suggested `ls` solutions, `find` is solely responsible for doing the job (not relying on shell wildcard expansion, which can impose limits). It also is a lot more concise. – peterp Apr 13 '14 at 08:54
  • 1
    The bad thing about this is that it doesn't work if you are trying to loop through the results and your results have spaces in the names. – ubiquibacon May 10 '14 at 18:39
  • 5
    Alternatively, if you didn't want to include the directory itself: `find * -maxdepth 0 -type d`. – James Ko Jun 20 '15 at 19:14
  • @ubiquibacon Either use `find`'s `-print0` or `-exec` option. –  Dec 10 '16 at 20:03
  • 1
    This is really slow, at least on my Mac. It seems to do the full recursive search that `find` usually does but only output the folders at depth 1. – Kara Brightwell Jun 08 '17 at 19:47
  • @MattBrennan - did you test this? `-depth 1` is definitely impractically slow, but `-maxdepth 1` is pretty quick. That said `ls -d {.*,*}/` is faster though. – ocodo Jan 08 '18 at 03:28
  • Note that this produces different results from the top `ls`-based solution, in the case of hidden files. This will include hidden files (although you can [explicitly exclude them](https://askubuntu.com/a/318211/320320)), whereas `ls -d */` does _not_ include hidden files. – Anders Rabo Thorbeck Jul 13 '18 at 11:00
28

The following

find * -maxdepth 0 -type d

basically filters the expansion of '*', i.e. all entries in the current dir, by the -type d condition.

Advantage is that, output is same as ls -1 *, but only with directories and entries do not start with a dot

nitinr708
  • 1,393
  • 2
  • 19
  • 29
radiospiel
  • 2,450
  • 21
  • 28
13

You can use ls -d */ or tree -d

Another solution would be globbing but this depends on the shell you are using and if globbing for directories is supported.

For example ZSH:

zsh # ls *(/)
echox
  • 9,726
  • 6
  • 33
  • 51
11
ls -l | grep '^d'

You can make an alias and put it into the profile file

alias ld="ls -l| grep '^d'"
fedorqui
  • 275,237
  • 103
  • 548
  • 598
somesh chandra
  • 119
  • 1
  • 3
  • 2
    links are not viewed with this command. And a link can be a file or a directory. Example : lrwxrwxrwx 1 root root 21 avril 15 17:38 cron -> /lib/init/upstart-job. – c-toesca Aug 23 '14 at 14:19
11

Since there are dozens of ways to do it, here is another one:

tree -d -L 1 -i --noreport
  • -d: directories
  • -L: depth of the tree (hence 1, our working directory)
  • -i: no indentation, print names only
  • --noreport: do not report information at the end of the tree listing
alleen1
  • 418
  • 6
  • 14
  • And thank you for explaining the switches. Stack Overflow is about answers, I always appreciate when people do just like you with an explanation vs. "just read the man entry!" <-- that's not an answer. – fusion27 Aug 20 '14 at 13:27
  • To start from line 2 (skip the line with only a dot): `tree -d -L 1 -i --noreport | tail -n +2` – adius Feb 08 '18 at 10:56
  • This is the highest-ranked solution that lists soft-linked directories and does so in a useful manner, exposing them as a link. I prefer the variation: `tree -C -d -L 1 -i --noreport | tail -n+2` – Amnon Harel Nov 08 '18 at 14:03
7
find . -maxdepth 1 -type d -name [^\.]\* | sed 's:^\./::'
yunzen
  • 32,854
  • 11
  • 73
  • 106
mda
  • 1,158
  • 14
  • 18
7

use this to get a list of directory

ls -d */ | sed -e "s/\///g"
fedorqui
  • 275,237
  • 103
  • 548
  • 598
Lakshmi
  • 71
  • 1
  • 2
6

In order to list the directories in current working directory ls -d */ can be used. And If you need to list the hidden directories use this command ls -d .*/

kvivek
  • 3,321
  • 1
  • 15
  • 17
6

The answer will depend on your shell.

In zsh, for example, you can do the following:

echo *(/)

And all directories within the current working directory will be displayed.

See man zshexpn for more information.

An alternative approach would be to use find(1), which should work on most Unix flavours:

find . -maxdepth 1 -type d -print  

find(1) has many uses, so I'd definitely recommend man find.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
5

find specifiedpath -type d

If you don't want to recurse in subdirectories, you can do this instead:

find specifiedpath -type d -mindepth 1 -maxdepth 1

Note that "dot" directories (whose name start with .) will be listed too; but not the special directories . nor ... If you don't want "dot" directories, you can just grep them out:

find specifiedpath -type d -mindepth 1 -maxdepth 1 | grep -v '^\.'

DomQ
  • 4,184
  • 38
  • 37
5

Long listing of directories

ls -l | grep  '^d'  

Listing directories

ls -d */
CoderGuy123
  • 6,219
  • 5
  • 59
  • 89
Athi
  • 61
  • 1
  • 4
4

You can use the tree command with its d switch to accomplish this.

% tree -d tstdir
tstdir
|-- d1
|   `-- d11
|       `-- d111
`-- d2
    `-- d21
        `-- d211

6 directories

see man tree for more info.

slm
  • 15,396
  • 12
  • 109
  • 124
2

If I have this directory:

ls -l

lrwxrwxrwx  1 nagios nagios     11 août   2 18:46 conf_nagios -> /etc/icinga
-rw-------  1 nagios nagios 724930 août  15 21:00 dead.letter
-rw-r--r--  1 nagios nagios  12312 août  23 00:13 icinga.log
-rw-r--r--  1 nagios nagios   8323 août  23 00:12 icinga.log.gz
drwxr-xr-x  2 nagios nagios   4096 août  23 16:36 tmp

To get all directories, use -L to resolve links:

ls -lL | grep '^d'

drwxr-xr-x 5 nagios nagios   4096 août  15 21:22 conf_nagios
drwxr-xr-x 2 nagios nagios   4096 août  23 16:41 tmp

Without -L:

ls -l | grep '^d'

drwxr-xr-x 2 nagios nagios   4096 août  23 16:41 tmp

conf_nagios directory is missing.

c-toesca
  • 947
  • 1
  • 11
  • 13
2

This has been working for me:

ls -F | grep /

(But, I am switching to echo */ as mentioned by @nos)

CoderGuy123
  • 6,219
  • 5
  • 59
  • 89
FractalSpace
  • 5,577
  • 3
  • 42
  • 47
2
### If you need full path of dir and list selective dir with "name" of dir(or dir_prefix*):
find $(pwd) -maxdepth 1 -type d -name "SL*"
Surya
  • 11,002
  • 4
  • 57
  • 39
2

In bash:

ls -d */

Will list all directories

ls -ld */

will list all directories in long form

ls -ld */ .*/

will list all directories, including hidden directories, in long form.


I have recently switched to zsh (MacOS Catalina), and found that:

ls -ld */ .*/

no longer works if the current directory contains no hidden directories.

zsh: no matches found: .*/

It will print the above error, but also will fail to print any directories.

ls -ld *(/) .*(/)

Also fails in the same way.

So far I have found that this:

ls -ld */;ls -ld .*/

is a decent workaround. The ; is a command separator. But it means that if there are no hidden directories, it will list directories, and still print the error for no hidden directories:

foo
bar
zsh: no matches found: .*/

ls is the shell command for list contents of current directory
-l is the flag to specify that you want to list in Longford (one item per line + a bunch of other cool information)
-d is the flag to list all directories "as files" and not recursively
*/ is the argument 'list all files ending in a slash'
* is a simple regex command for "anything", so */ is asking the shell to list "anything ending in '/'"

See man ls for more information.


I put this:

alias lad="ls -ld */;ls -ld .*/"

in my .zshrc, and it seems to work fine.

NOTE: I've also discovered that

ls -ld .*/ 2> /dev/null

doesn't work, as it still prints sterr to the terminal. I'll update my answer if/when I find a solution.

DryLabRebel
  • 8,923
  • 3
  • 18
  • 24
1

Here's another solution that shows linked directories. I slightly prefer it because it's a subset of the "normal" ls -l output:

ls -1d */ | rev | cut -c2- | rev | xargs ls -ld --color=always
Amnon Harel
  • 151
  • 1
  • 4
1

To list only directories in a specified path,just type

ls -l | grep drw
CoderGuy123
  • 6,219
  • 5
  • 59
  • 89
Loui
  • 97
  • 2
  • 11
  • This might include files, if any filenames include `drw`, and would exclude any directories that are not owner-readable and -writeable. `grep ^d` works better. – Tom Zych Sep 29 '19 at 07:29
1

This is the answer most people will want.

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

The directory names, and nothing but the directory names.

CoderGuy123
  • 6,219
  • 5
  • 59
  • 89
Anthony Rutledge
  • 6,980
  • 2
  • 39
  • 44
1

I find there are many good answers listed before me. But I would like to add a command which we already use it several time, and so very easy to list all the directories with less effort:

cd

(Note: After cd give a space) and press tab twice, it will list only all the directories in current working directory. Hope this is easy to use. Please let me know if there is any problem with this. Thanks.

kamalesh d
  • 17
  • 1
  • 4
1

For a Bash script, I would typically try to do it in a way that does not execute any external program (grep, sed, ls, ...)

for i in * ; do 
  if [[ -d "$i" ]] ; then
    echo "$i" 
  fi
done 

or as a single compact line

for i in * ; do [[ -d "$i" ]] && echo "$i" ; done 

And if I need to reuse the list of directories, I would typically put it into an array:

DIRS=() ; for i in * ; do [[ -d "$i" ]] && DIRS+=("$i") ; done 

and then use "${DIRS[*]}" or "${DIRS[@]}" to expand the array as in

for dir in "${DIRS[@]}" ; do 
   echo "Do something with directory $dir"
done

Another benefit of that approach is that it is very robust. It can handle spaces and newline in the directory names.

Stef
  • 11
  • 1
0

du -d1 is perhaps the shortest option. (As long as you don't need to pipe the input to another command.)

Mohan
  • 7,302
  • 5
  • 32
  • 55