126

Sometimes, I need to check only the directories not files. Is there any option with the command ls? Or is there any utility for doing that?

EDIT: I'm using Mac OS X, and ls -d gives me . even though I have directories.

tshepang
  • 65,642
prosseek
  • 8,558
  • 4
    Can somebody explain why ls -d gives only . and why the */ must be added to the end to make it work? – cwd Oct 04 '11 at 02:49
  • 5
    @cwd If you don't specify any files, ls defaults to .. And -d means don't print the directory's contents, print the directory itself. – Mikel May 23 '12 at 14:52
  • 1
    @cwd try using ls -p it shows the / after the directory names. So */ is just a pattern which is matched against the directory name and / combo. – Pitt Oct 24 '12 at 15:55
  • I created a function implementing @Steven_D's answer for my ~/.bash_aliases file: https://gist.github.com/rjurney/998f4951a57bfa5daeb9a6c18f6f4827 – rjurney Oct 04 '19 at 15:49

11 Answers11

146

I know there is already a selected answer, but you can get the requested behavior with just ls:

ls -ld -- */

(Note that the '--' marks the end of parameters, preventing folder names beginning with a hyphen from being interpreted as further command options.)

This will list all the non-hidden (unless you configure your shell's globs to expand them) directories in the current working directory where it is run (note that it also includes symbolic links to directories). To get all the subdirectories of some other folder, just try:

ls -ld /path/to/directory/*/

Note that the -l is optional.

Steven D
  • 46,160
  • 7
    Nice. I never considered that directories have an implicit / on the end--but now that I see you answer it makes sense. After all, tab-completion always adds it. – gvkv Sep 06 '10 at 03:46
  • -d for dir, -l for long format. whats the purpose of -- ? – Dineshkumar Apr 17 '15 at 15:03
  • 1
    While this looks short and works for most cases, one may not want to use this approach when a true directory is needed, not a directory's symlink. So find is actually a good choice in that case. – biocyberman Jan 31 '17 at 20:59
  • 2
    find also has the advantage when the number of directories exceeds the maximum argument length. – Steven D Feb 01 '17 at 09:31
  • Working backwards, I just realised you can simply ignore anything with an extension: ls -alhF --ignore=*.*. Not sure how well this would handle 'hidden' folders, i.e. .myHiddenFolder – Timmah Nov 01 '17 at 00:46
  • I created a function to do this called by the command lsd: https://gist.github.com/rjurney/998f4951a57bfa5daeb9a6c18f6f4827 – rjurney Oct 04 '19 at 15:48
  • 1
    Just a note on @Timmah s comment: Directories may also contain dots in their name. – Michael K Jan 20 '21 at 07:43
  • This does not list only directories as requested – d.c. Jan 10 '22 at 16:57
26

No, but a simple find command will do it (here using the -{min,max}depth GNU extensions, also found on most implementations theses days):

find . -mindepth 1 -maxdepth 1 -type d

Or the POSIX (standard) equivalent:

find . ! -name . -prune -type d

On FreeBSD and some of its derivatives (including macOS), you can also do:

find . -depth 1 -prune -type d

Those also include hidden directories (not the . or .. special directories) and don't sort the list of files. It also adds a ./ prefix to each file which with the GNU implementation of find, you can remove by adding -printf '%P\n'.

or grep (assuming file names don't contain newline characters):

ls -p | grep /

(add the -A option to ls to include hidden ones).

You could then alias either one if necessary.

gvkv
  • 2,738
  • 10
    On Ubuntu 14.04 it was -maxdepth 1. Also find wanted me to flip the order: find . -maxdepth 1 -type d – Brad Cupit Aug 28 '15 at 14:33
  • That ls -F | grep / solution works wonders! It seems to be the only one I can get to work on my FreeBSD machine. I think using Fish means that anything with */ may not work? – cjm Jul 27 '16 at 04:38
  • I've never worked with Fish so I'm not sure about that but the -F option can work wonders. – gvkv Jul 27 '16 at 13:21
  • 1
    This gives me errors on Linux Mint with find version 4.4.2. I get find: warning: you have specified the -depth option after a non-option argument -type, but options are not positional (-depth affects tests specified before it as well as those specified after it). Please specify options before other arguments. (If I use maxdepth instead I still get the warning, but it's followed by the correct output.) – felwithe Sep 15 '21 at 21:27
  • 1
    @EricLeschinski, the functional equivalent of FreeBSD's -depth 1 with GNU find's -{min,max}depth would be -mindepth 1 -maxdepth 1. FreeBSD's -depth 1 yields true for files at depth 1, but doesn't otherwise stop find from descending into subdirectories, so -mindepth 1 -maxdepth 1 (which is now also supported by all BSDs including FreeBSD) is better, though you could also do find . -depth 1 -prune -type d to get something equivalent. – Stéphane Chazelas Jan 10 '22 at 16:20
9

I also needed to view hidden directories so have modified the suggestion above to fit my needs

ls -d -- */ .*/

(depending on the shell, that may also include . and ..)

  • Then there's ls -a to include directory entries whose names begin with a dot (.), which avoids the annoyance of matching . and ... – nclark Feb 03 '20 at 14:50
8

I like the tree utility to get an overview over the directory structure. It's available in MacPorts and all Linux distributions I've tried.

tree -d -L 2

That would show all directories, two levels deep.

3

With zsh (as found by default on macOS, it even used to be /bin/sh there, and it's the default login shell in newer versions), you'd use glob qualifiers to select files based on their type:

  • List non-hidden directories:

    ls -ld -- *(/)
    
  • List all directories:

    ls -ld -- *(D/)
    

    (. and .. are always excluded, add them individually if you want them)

  • Also include symlinks to directories:

    ls -ld -- *(D-/)
    

    (- makes so further qualifiers apply after symlink resolution).

Here, using -l to get a long listing. For printing the list of matching files, you don't need ls, you can replace ls -ld with print -rC1 (print raw on 1 Column, print being builtin). You may also want to add the N glob qualifier so as to print nothing if there's no matching file instead of reporting an error:

print -rC1 -- *(ND/)
0

There is not just one option to list directories...

But you can use -d (list directories themselves, not their contents) and */ to match directories themselves:

ls -d */

And try to use the dot, for hidden ones, ls -d .*/.

Just for fun, try: ls -d and ls */. The differences will be clear!

Ref:

marcio
  • 141
  • 1
    Note that the accepted answer basically shows this already, together with -- to protect against interpreting directory names starting with a dash as options. – Kusalananda Jan 02 '20 at 21:32
  • This is a good link. There the tag "bash" is set. I only found "If followed by a /...." in man bash. in "Pathname Expansion", explaining "*". –  Jan 03 '20 at 00:09
  • Kusalananda, pls, read the first line from Steven D answer... Mine is just shorter. And I clarify the option and the match. Thank you for your attention! – marcio Jan 03 '20 at 14:24
  • 1
    Now the second (SE) link lacks the "bash" tag, and patrick's answer elegantly avoids explanations. If you compare with the zsh solution just above, you see it is a shell thing about extended pattern matching. Where is that */ notation in bash defined? –  Jan 03 '20 at 17:12
  • 1
    What I meant in my previous comment was that the accepted answer will not start to behave strangely when there is a file or directory called, e.g., -l in the current directory. – Kusalananda Jan 03 '20 at 17:20
  • Yes rastafile, https://stackoverflow.com/a/31603260/12453339 is a good explanation, really undervoted... – marcio Jan 03 '20 at 18:12
0

Use ls command like this

❯ ls -1d plugins/*/
plugins/localizable/
plugins/redmine_agile/
plugins/redmine_gitlab_hook/
plugins/redmine_mermaid_macro/
plugins/redmine_open_links_in_new_window/
Sunding Wei
  • 101
  • 1
-1
$ ls -p | grep /

The -p flag will make ls add a slash (`/') after each filename if that file is a directory.

Kusalananda
  • 333,661
-2

I think ls has a bug on Mac OS X. A workaround is to use grep... ls -l / | grep "^d"

  • 1
    It's nice to know I'm not the only person that uses the grep "^d" hack – Michael Mrozek Sep 06 '10 at 02:10
  • 7
    As far as I know, the behavior he describes is not a bug and is the same if one is using GNU ls. The -d option displays the listing for the directory and not the contents. To see why this can be useful see the difference between: ls -l /home and ls -dl /home – Steven D Sep 06 '10 at 02:11
  • 1
    Carats aren't special to the shell. You can just use ls -l / | grep ^d. If you are going to use quotes, since you don't need parameter expansion, make them single quotes. ls -l / | grep '^d'. Yes, I'm a pedant. But really, do this. :) – Wildcard Nov 01 '16 at 01:08
-3
ls -G

this will show your directories in blue

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
-3

The easiest way is to type the following command. This works across most UNIX and Linux platforms and versions. You can skip the -F if you want, but it is the argument that adds the / to the end of the directory name. The -C argument captures only directory names - all of them in the current directory. If you want to see only directories and subdirectories in the current path, simply add the -R argument (ls -CFR).

# ls -CF
/dir1  /dir2  /dir3  /beaches  /Work  /Other 
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • 1
    In all ls implementations I know and in the POSIX specification of ls, -C is to output in columns, not to skip non-directory files. In your example, the / are printed before the file names, which no ls implementation would do. With -F, / is appended to the file name for directory files. – Stéphane Chazelas Jun 21 '18 at 16:15
  • When I saw this answer, I wondered “Where is this true?” @StéphaneChazelas and Jeff Schaller — don’t you downvote blatantly wrong answers? – G-Man Says 'Reinstate Monica' Feb 21 '19 at 03:51
  • This doesn't work on Ubuntu 18.04. standard terminal – somethis Apr 25 '21 at 22:12