The command 'ls -d' is not displaying directories. Is there a way to get 'ls' to only display directories instead of files and directories?

68,160

Solution 1

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.

Solution 2

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

Solution 3

Try this

 find . -mindepth 1 -maxdepth 1 -type d

to get just directories under your current location.

Solution 4

You might also like

tree -d 

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

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

Share:
68,160

Related videos on Youtube

nelaaro
Author by

nelaaro

Linux admin, tech enthusiast. opensource evangelist.

Updated on September 18, 2022

Comments

  • nelaaro
    nelaaro almost 2 years

    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?

    • boehj
      boehj over 12 years
      lsd can be very confusing.
    • nelaaro
      nelaaro over 12 years
      @jin ls -d */ works. But why do I have to "*/" to get the out put I want.
    • Jin
      Jin over 12 years
      @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.
    • DQdlM
      DQdlM over 12 years
      I have ldir alised to ls -d */ in my .bashrc to make this easier...
    • Gaff
      Gaff over 12 years
    • DimiDak
      DimiDak over 5 years
      ls can give you tons of information but not one single flag for just showing directories...
  • nelaaro
    nelaaro over 12 years
    thanks you. I realize I was not thinking about wildcard expansion correctly. You have clarified that very well for me. You have helped a lot. I can actually say I get it.
  • Random832
    Random832 over 12 years
    "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]
  • JdeBP
    JdeBP over 12 years
    It's a strong and true statement for a system like Unix where wildcard expansion is divorced from entry type checking. Your hypothetical implementation is erroneous. What you describe still expands * to include the non-directories, with all of the filesystem race conditions and subtle scripting connotations that that entails. Whereas dir /a:d will, on operating systems that have this functionality in the system API, skip non-directories immediately without even returning them to application-mode code.
  • Random832
    Random832 over 12 years
    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".
  • JdeBP
    JdeBP over 12 years
    Kiddo, it's not only relevant; it's the core of the problem. If you don't understand that, you don't understand one of the fundamentals of Unix. Think! Start by re-reading what I wrote and think about what race conditions and subtle scripting connotations I referred to. The race conditions are fairly well known, and the scripting connotations can be seen with a little applied thought.
  • nom-mon-ir
    nom-mon-ir over 11 years
    clever trick using the / !
  • Thanatos
    Thanatos over 11 years
    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.
  • ocodo
    ocodo almost 11 years
    This is going to filter out more than directories.
  • Anne van Rossum
    Anne van Rossum over 10 years
    And for only one level deep: tree -dL 1
  • JdeBP
    JdeBP over 10 years
    You and Thanatos, even though I've explained it twice already, have entirely missed the point. It's not about ls being altered to treat directories differently, as if somehow it didn't already. We know that it can and it does. That is right there in the answer. You've both not thought about what I said to think about, including the fundamentals of Unix, which mean that there's no way for an option to ls to control shell wildcard expansion. Random832 was specifically contradicting that statement of mine, and providing as supposed proof a mechanism that doesn't actually work as claimed.
  • iyrin
    iyrin over 9 years
    Yeah this is good. Is there any case where this doesn't work?
  • mkalkov
    mkalkov almost 9 years
    @Slomojo, this will filter out everything but directories. What did you mean?
  • mkalkov
    mkalkov almost 9 years
    It may be even better to use find -maxdepth 1 -type d -exec ls -d {} + to get output in the usual lsformat.
  • mkalkov
    mkalkov almost 9 years
    @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.
  • Calculus Knight
    Calculus Knight over 8 years
    +1 for providing the answer in one line. I'm guessing the accepted answer also has it, somewhere.
  • neuronet
    neuronet about 8 years
    Answer is pedantic and presumptuous. Consider ls -l which lists all the stuff in the working directory. One might very reasonably expect ls -d to just list all the directories in the current directory (especially given the output of man ls, which OP quoted). The convention of showing everything in the working directory, subject to some constraint set by an option flag, is ubiquitous in bash. There is nothing weird or MSDOSish about it at all. Whatever happened to just answering the question.
  • geoO
    geoO over 7 years
    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.
  • DimiDak
    DimiDak over 5 years
    Unfortunately you can't combine much with tree. # tree -d | grep wc -l (standard input)
  • DimiDak
    DimiDak over 5 years
    Ls could just add the "directories only" flag. With this hack "ls -d */" you have to be in the directory to see subdirectories.
  • DimiDak
    DimiDak over 5 years
    How can you use this in a script without being in the directory already?
  • felwithe
    felwithe about 3 years
    Myy expectations have nothing to do with Windows. Have a downvote. I didn't read the rest.