[linux] counting number of directories in a specific directory

How to count the number of folders in a specific directory. I am using the following command, but it always provides an extra one.

find /directory/ -maxdepth 1 -type d -print| wc -l

For example, if I have 3 folders, this command provides 4. If it contains 5 folders, the command provides 6. Why is that?

This question is related to linux bash

The answer is


A pure bash solution:

shopt -s nullglob
dirs=( /path/to/directory/*/ )
echo "There are ${#dirs[@]} (non-hidden) directories"

If you also want to count the hidden directories:

shopt -s nullglob dotglob
dirs=( /path/to/directory/*/ )
echo "There are ${#dirs[@]} directories (including hidden ones)"

Note that this will also count links to directories. If you don't want that, it's a bit more difficult with this method.


Using find:

find /path/to/directory -type d \! -name . -prune -exec printf x \; | wc -c

The trick is to output an x to stdout each time a directory is found, and then use wc to count the number of characters. This will count the number of all directories (including hidden ones), excluding links.


The methods presented here are all safe wrt to funny characters that can appear in file names (spaces, newlines, glob characters, etc.).


The best answer to what you want is

echo `find . -maxdepth 1 -type d | wc -l`-1 | bc

this subtracts one to remove the unwanted '.' directory that find lists (as patel deven mentioned above).

If you want to count subfolders recursively, then just leave off the maxdepth option, so

echo `find . -type d | wc -l`-1 | bc

PS If you find command substitution ugly, subtracting one can be done as a pure stream using sed and bc.

Subtracting one from count:

find . -maxdepth 1 -type d | wc -l | sed 's/$/-1\n/' | bc

or, adding count to minus one:

find . -maxdepth 1 -type d | wc -l | sed 's/^/-1+/' | bc

Using zsh:

a=(*(/N)); echo ${#a}

The N is a nullglob, / makes it match directories, # counts. It will neatly cope with spaces in directory names as well as returning 0 if there are no directories.


Best way to do it:

ls -la | grep -v total | wc -l

This gives you the perfect count.


No of directory we can find using below command

ls -l | grep "^d" | wc -l


find is also printing the directory itself:

$ find .vim/ -maxdepth 1 -type d
.vim/
.vim/indent
.vim/colors
.vim/doc
.vim/after
.vim/autoload
.vim/compiler
.vim/plugin
.vim/syntax
.vim/ftplugin
.vim/bundle
.vim/ftdetect

You can instead test the directory's children and do not descend into them at all:

$ find .vim/* -maxdepth 0 -type d
.vim/after
.vim/autoload
.vim/bundle
.vim/colors
.vim/compiler
.vim/doc
.vim/ftdetect
.vim/ftplugin
.vim/indent
.vim/plugin
.vim/syntax

$ find .vim/* -maxdepth 0 -type d | wc -l
11
$ find .vim/ -maxdepth 1 -type d | wc -l
12

You can also use ls:

$ ls -l .vim | grep -c ^d
11


$ ls -l .vim
total 52
drwxrwxr-x  3 anossovp anossovp 4096 Aug 29  2012 after
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 autoload
drwxrwxr-x 13 anossovp anossovp 4096 Aug 29  2012 bundle
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 colors
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 compiler
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 doc
-rw-rw-r--  1 anossovp anossovp   48 Aug 29  2012 filetype.vim
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 ftdetect
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 ftplugin
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 indent
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 plugin
-rw-rw-r--  1 anossovp anossovp 2505 Aug 29  2012 README.rst
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 syntax

$ ls -l .vim | grep ^d
drwxrwxr-x  3 anossovp anossovp 4096 Aug 29  2012 after
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 autoload
drwxrwxr-x 13 anossovp anossovp 4096 Aug 29  2012 bundle
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 colors
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 compiler
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 doc
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 ftdetect
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 ftplugin
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 indent
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 plugin
drwxrwxr-x  2 anossovp anossovp 4096 Aug 29  2012 syntax

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

For find -mindepth means total number recusive in directories

-maxdepth means total number recusive in directories

-type d means directory

And for wc -l means count the lines of the input


Get a count of only the directories in the current directory

echo */ | wc

you will get out put like 1 309 4594

2nd digit represents no. of directories.

or

tree -L 1 | tail -1


Some useful examples:

count files in current dir

/bin/ls -lA  | egrep -c '^-'

count dirs in current dir

/bin/ls -lA  | egrep -c '^d'

count files and dirs in current dir

/bin/ls -lA  | egrep -c '^-|^d'

count files and dirs in in one subdirectory

/bin/ls -lA  subdir_name/ | egrep -c '^-|^d'

I have noticed a strange thing (at least in my case) :

When I have tried with ls instead /bin/ls the -A parameter do not list implied . and .. NOT WORK as espected. When I use ls that show ./ and ../ So that result wrong count. SOLUTION : /bin/ls instead ls


Run stat -c %h folder and subtract 2 from the result. This employs only a single subprocess as opposed to the 2 (or even 3) required by most of the other solutions here (typically find plus wc).

Using sh/bash:

cnt=$((`stat -c %h folder` - 2))
echo $cnt   # 'echo' is a sh/bash builtin, not an additional process

Using csh/tcsh:

@ cnt = `stat -c %h folder` - 2
echo $cnt   # 'echo' is a csh/tcsh builtin, not an additional process


Explanation: stat -c %h folder prints the number of hardlinks to folder, and each subfolder under folder contains a ../ entry which is a hardlink back to folder. You must subtract 2 because there are two additional hardlinks in the count:

  1. folder's own self-referential ./ entry, and
  2. folder's parent's link to folder

If you want to use regular expressions, then try:

ls -c | grep "^d" | wc -l

Count all files and subfolders, windows style:

dir=/YOUR/PATH;f=$(find $dir -type f | wc -l); d=$(find $dir -mindepth 1 -type d | wc -l); echo "$f Files, $d Folders"

I think the easiest is

  ls -ld images/* | wc -l

where images is your target directory. The -d flag limits to directories, and the -l flag will perform a per-line listing, compatible with the very familiar wc -l for line count.


If you only have directories in the folder and no files this does it:

ls | wc -l

Best way to navigate to your drive and simply execute

ls -lR | grep ^d | wc -l

and to Find all folders in total, including subdirectories?

find /mount/point -type d | wc -l

...or find all folders in the root directory (not including subdirectories)?

find /mount/point -maxdepth 1 -type d | wc -l

Cheers!