47

Is there a way to get ls to only display directories instead of files and directories?

From the man page:

   -d, --directory
          list directory entries instead of contents, and do not  derefer‐
          ence symbolic links

So if I type it at the / directory I expect to see only directories. Instead it shows "."

$ cd /
$ ls -d
.

I was expecting ls -d to show me this:

$ ls -d
bin    data  home        opt    sbin  sys      var
boot   dev   lib         media  proc  selinux  tmp
cdrom  etc   lost+found  mnt    root  srv      usr

Is there a way to get ls to only display directories instead of files and directories?

6
  • 18
    lsd can be very confusing.
    – boehj
    Oct 10, 2011 at 9:12
  • 2
    @jin ls -d */ works. But why do I have to "*/" to get the out put I want.
    – nelaaro
    Oct 10, 2011 at 9:33
  • 8
    @nelaar -d doesn't mean to list directories only, it means to not list directory contents. Try typing ls */ and you'll see the contents of all the directories.
    – Jin
    Oct 10, 2011 at 9:45
  • 2
    I have ldir alised to ls -d */ in my .bashrc to make this easier...
    – DQdlM
    Oct 10, 2011 at 11:09
  • 1
    ls can give you tons of information but not one single flag for just showing directories...
    – DimiDak
    Feb 15, 2019 at 14:00

7 Answers 7

51

Your expectations are based upon DOS Think/Windows Think and are wrong. On MS-DOS, Windows, and indeed a few other IBM/Microsoft operating systems, wildcard expansion is done by the command itself, and things like the /a option to the dir command act as attribute filters during wildcard expansion. dir expands wildcards like *, which the command interpreter passes to it as-is, and if /a is specified it applies the appropriate filters to what is returned. (On some operating systems, the attribute filters can be given to the system call for enumerating a directory and the operating system kernel, or its filesystem drivers, applies them itself.)

On Unices and on Linux, wildcard expansion is done by the shell, and is oblivious to permissions. When, in the root directory, you do

ls *

what the ls command itself receives from the shell is (something like)

ls bin home opt var boot dev tmp etc lost+found root usr

What the -d/--directory option does is turn off what normally happens next. What normally happens next is that ls looks at each of its arguments in turn, sees that they are directories, and decides to enumerate their contents. For arguments that name files, it just prints out the information for the file itself. With the -d option, directories are treated just like files. So ls prints out the information for each of the directories that is passed as its arguments, just as it would do if they were files.

So -d is not a "print only directories" option. In fact, not only is there no such option; there cannot be such an option. Wildcard expansion is done by the shell, and (in a POSIX sh at least) there's no way to tell the shell to check permission and file type bits when it expands * into a list of names. To obtain a list of the names of directories alone, it is necessary either to use the find command, as explained by ztank1013, or to use the trick that a pathname ending with a slash implies the directory entry ., as explained by Jin. (Jin's trick ends up with the ls command receiving the arguments

ls bin/ home/ opt/ var/ boot/ dev/ tmp/ etc/ lost+found/ root/ usr/

because the pattern */ is in fact matching pathnames with two components, the second being empty, and so isn't quite doing what was desired. In particular, it will treat symbolic links pointing to directories as if they were directories.)

The behaviour of ls -d without a * is a simple extension of the above. One simply has to know one more thing about ls: When it is given no arguments, it assumes a default argument of .. Now without the -d option, the aforementioned behaviour leads to the contents of the directory named by . being enumerated and the information for its contents displayed. With the -d option, the directory . is treated just as if it were a file, and its own information is displayed, rather than its contents enumerated.

12
  • 3
    "there cannot be such an option" - that's a rather strong statement - the implementation of such an option is obvious: see a non-directory argument and ignore it. What can't be implemented is the equivalent of dir /s *.txt [without resorting to quoting wildcards as for find]
    – Random832
    Oct 10, 2011 at 13:25
  • 6
    Right, but there's no logical reason ls can't have an option which will filter out items that were passed in as arguments. The fact that "wildcard expansion is divorced from entry type checking" is irrelevant, since this has nothing at all to do with wildcard expansion - only entry type checking, which there is no reason it cannot be done entirely within ls. If ls --color can shade them blue, ls -F can put a / after them, and ls -l can put a 'd' in the mode, then some other hypothetical option could omit them. That such an option does not exist doesn't mean it "cannot".
    – Random832
    Oct 10, 2011 at 17:15
  • 5
    Random832 makes a decent point: ls could have an option to filter files or directories, and this isn't mutually exclusive with having the shell do expansion. There's no race condition within ls: it can filter it as it stats the files normally. (There is already a race between the shell expansion and ls, FWIW.) I think shell expansion is only part of the reason: shell expansion (and filtering in general) is not implemented in ls because it would need to be implemented again in cp, mv, etc. Unix is a "do one thing and do it well". If you need advanced filtering, there are tools for that.
    – Thanatos
    Mar 20, 2013 at 5:45
  • 2
    The ls -p option adds a / symbol to directories only. There is no reason not to extend the output printing capabilities with something that does only output these (rather than ls -p | grep /). Mar 14, 2014 at 9:00
  • 3
    @JdeBP, ad-hominem attacks ("kiddo") and arrogance (everybody except you does not know "the fundamentals of Unix") do not belong to a technical discussion. Furthermore, you're pulling a straw man when you argue that a command option cannot control wildcard expansion done by shell. Of course, it cannot! Neither Random832, nor Thanatos, nor Anne van Rossum, and not even the question itself mention wildcards in any way. The objection was that ls --only-directories . option could be added to ls eventually.
    – mkalkov
    Aug 7, 2015 at 9:51
30

You can usels -d */, or ls -d .*/ for hidden directories.

4
  • clever trick using the / !
    – nom-mon-ir
    Mar 8, 2013 at 23:39
  • Yeah this is good. Is there any case where this doesn't work?
    – iyrin
    Feb 7, 2015 at 23:11
  • 5
    +1 for providing the answer in one line. I'm guessing the accepted answer also has it, somewhere. Sep 28, 2015 at 15:25
  • How can you use this in a script without being in the directory already?
    – DimiDak
    Feb 15, 2019 at 14:09
13

Try this

 find . -mindepth 1 -maxdepth 1 -type d

to get just directories under your current location.

0
5

You might also like

tree -d 

which neatly lists all directories and subdirectories with a graphical depiction of the tree structure.

2
  • 3
    And for only one level deep: tree -dL 1 Mar 14, 2014 at 9:14
  • Unfortunately you can't combine much with tree. # tree -d | grep wc -l (standard input)
    – DimiDak
    Feb 15, 2019 at 14:02
5

If you want to see directories only with detail like ls -l (ELL) option then you can use below:

find -maxdepth 1 -type d -ls;

Above will only give you the detail like you get with the -l option.

1
  • 1
    It may be even better to use find -maxdepth 1 -type d -exec ls -d {} + to get output in the usual lsformat.
    – mkalkov
    Aug 7, 2015 at 9:40
4

If you want to get the job done in another way, try this:

ls -l | grep ^d

Although a single tool is enough in this situation. Pipe line is always there to help you. I like the flexibility in Linux, which I wish you do.

3
  • 1
    This is going to filter out more than directories.
    – ocodo
    Sep 1, 2013 at 0:05
  • 2
    @Slomojo, this will filter out everything but directories. What did you mean?
    – mkalkov
    Aug 7, 2015 at 9:37
  • Yeah, you need the -l (long) so that permissions head up the line. "d" for directory. Plus you get a "long" listing of a directory entry which is nice.
    – geoO
    Dec 29, 2016 at 5:30
1

I hope this will rectify your need. The below command will list only directories in a given path.

ls -F <path> | grep /

Example:

ls -F ~ | grep /

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .