Thursday, March 18, 2010

Listing only directories

The ls command lists contents of a directory. A common desire is to see only contents that are themselves directories. Minor facility with other commands help ls achieve the goal.

First let us set up a concrete example. Suppose that there is a directory called ~/tmp that contains both files and directories, 98 to be exact.

~/tmp$ ls -l | wc -l
98

To winnow out files one must be able to distinguish a directory from a file. A simple solution is to use the -d switch of ls (thanks go to Jeffrey for this method).

~/tmp$ ls -d */
aa/  bin/  CYI/  ImageJ/  LaTeX/             Picasa-10091104/  pst-pdf/
av/  cfg/  ek/   kut/     p011-ursys-LaTeX/  pst/              sv/

The listing is nice and tight. If a line-oriented output is required, the -1 (that's a number 1) switch achieve the desired result.

In the remainder of this article we describe how to use other Unix tools in concert with ls to solve the problem. The -F switch appends an indicator to the names of certain types of content, and in particular a / is placed at the end of a directory name. The grep command can now be used to search for / at the end of the line.

~/tmp$ ls -F | grep '/$'
aa/
av/
bin/
cfg/
CYI/
ek/
ImageJ/
kut/
LaTeX/
p011-ursys-LaTeX/
Picasa-10091104/
pst/
pst-pdf/
sv/

Another way to distinguish a directory is to use the fact that the letter d is the first character in a long listing using the -l switch. Again grep can be used to select only lines that begin with d.

~/tmp$ ls -l | grep '^d'
drwxr-xr-x  4 tcburt tcburt     4096 2009-10-21 05:45 aa
drwxr-xr-x  4 tcburt tcburt     4096 2009-11-05 06:06 av
drwxr-xr-x  2 tcburt tcburt     4096 2009-03-15 14:10 bin
drwxr-xr-x  5 tcburt tcburt     4096 2009-03-15 14:10 cfg
drwxr-xr-x 11 tcburt tcburt     4096 2010-03-17 06:36 CYI
drwxr-xr-x  2 tcburt tcburt     4096 2009-07-12 18:50 ek
drwx------  6 tcburt tcburt     4096 2009-10-15 22:29 ImageJ
drwxr-xr-x  2 tcburt tcburt     4096 2009-12-10 20:47 kut
drwxr-xr-x  3 tcburt tcburt     4096 2009-06-14 17:51 LaTeX
drwxr-xr-x  2 tcburt tcburt     4096 2009-09-13 22:30 p011-ursys-LaTeX
drwxr-xr-x  4 tcburt tcburt     4096 2009-11-04 06:17 Picasa-10091104
drwxr-xr-x  2 tcburt tcburt     4096 2009-12-23 11:51 pst
drwxrwxr-x  3 tcburt tcburt     4096 2009-12-23 11:41 pst-pdf
drwxr-xr-x  4 tcburt tcburt     4096 2009-11-05 06:02 sv

The methods above satisfy the requirement of identifying only directories. However, they also result in additional characters besides just the names. The ls -F method lends itself to simply deleting the / character with the help of the tr command.

~/tmp$ ls -F | grep '/$' | tr -d /
aa
av
bin
cfg
CYI
ek
ImageJ
kut
LaTeX
p011-ursys-LaTeX
Picasa-10091104
pst
pst-pdf
sv

The pathological case where a / is part of the file name will not be served by the tr -d / invocation.

Recall that the long listing example did not leave a trailing slash on the directory name, it did prepend detailed information. For this case one needs to obtain only the final column which is the name itself. The perl command can split each line and print only the final column.

~/tmp$ ls -l | grep '^d' | perl -lane 'print "$F[-1]"'
aa
av
bin
cfg
CYI
ek
ImageJ
kut
LaTeX
p011-ursys-LaTeX
Picasa-10091104
pst
pst-pdf
sv

If listing only directories is a common task, it will be wise to define an alias for a favored method.

2 comments:

  1. find -type d -maxdepth 0

    or even better

    ls -d */

    ReplyDelete
  2. Thank you Jeffrey for the pointers. The 'ls -d */' works nicely and is now part of the article. However, the use of 'find' did not immediately work and warned that options must come before arguments. Rearranging did not obtain the desired result, so this becomes another open question for me.

    ReplyDelete