When displaying directories using ls -l, their number of links (the second field in the output) is at least two: one for the dir name and one for .

$ mkdir foo
$ ls -l
total 2
drwxr-xr-x  2 user   wheel  512  4 oct 14:02 foo

Is it safe to always assume that the number of links above 2 corresponds to the number of subdirectories in this dir (.. links) ?


It is usually true on unix systems that the number of links to a directory is the number of subdirectories plus 2. However there are cases where this is not true:

  • Some unices allow hard links to directories. Then there will be more than 2 links that do not correspond to subdirectories.

  • There are filesystems where directories do not have entries for . and ... The GNU find manual mentions some examples in the discussion of its -noleaf option (which disables an optimization that assumes that . and .. exist in all directories): “CD-ROM or MS-DOS filesystems or AFS volume mount points”

An almost reliable way to count the number of subdirectories (it may still fail if a file name contains a newline character) is

$(($(LC_ALL=C ls -la /path/to/directory | grep '^d' | wc -l) - 2)

A more reliable way uses shell globs */ and .*/; as usual handling the case where the pattern doesn't match is a bit of a pain (except in bash and zsh where you can turn on the nullglob option).


Here's yet another way to count subdirectories (non-recursively) in Bash:

shopt -s nullglob dotglob
printf '%s\000' */ | tr -dc '\0' | wc -c  # wc counts null bytes

Because each file name is being terminated by an ASCII NUL character, this should work correctly even if a file name contains a newline character.


You could try with:

ls -l |grep ^d | wc -l

I can't find anything in the documentation that confirms that the number of links will always be +2 on the number of subdirectories.

But, to find the correct ammount, use:

find . -type d -mindepth 1  -maxdepth 1 | wc -l

Or if you have to use ls -l, see the other answer.

  • 1
    I think you meant -type d, but: 1. this requires GNU find; 2. you need to subtract 1 for the starting directory (or pass -mindepth 1). Oct 4 '10 at 20:11

Don't use ls for this. Here's one way which works with all filenames, even those containing newlines, because it prints only a newline character instead of the filename:

find . -mindepth 1 -maxdepth 1 -type d -printf '\n' | wc -l

Edit: The current version doesn't result in any warnings, because -mindepth and -maxdepth should be before -type (the directory tree is pruned before checking for directories, to save time).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.