105

I want to see how many files are in subdirectories to find out where all the inode usage is on the system. Kind of like I would do this for space usage

du -sh /*

which will give me the space used in the directories off of root, but in this case I want the number of files, not the size.

9
  • I think that "how many files are in subdirectories in there subdirectories" is a confusing construction. If more clearly state what you want, you might get an answer that fits the bill.
    – Steven D
    Commented Nov 18, 2010 at 0:02
  • @Steven feel free to rewrite it... I thought my example of du -sh /* made it pretty clear how I wanted the count to work. same thing, just count the files not the bytes. Commented Nov 18, 2010 at 7:45
  • As you mention inode usage, I don't understand whether you want to count the number of files or the number of used inodes. The two are different when hard links are present in the filesystem. Most, if not all, answers give the number of files. Don't use them on an Apple Time Machine backup disk.
    – mouviciel
    Commented Nov 19, 2010 at 12:45
  • @mouviciel this isn't being used on a backup disk, and yes I suppose they might be different, but in the environment I'm in there are very few hardlinks, technically I just need to get a feel for it. figure out where someone is burning out there inode quota. Commented Nov 19, 2010 at 15:57

12 Answers 12

125
find . -maxdepth 1 -type d | while read -r dir
do printf "%s:\t" "$dir"; find "$dir" -type f | wc -l; done

Thanks to Gilles and xenoterracide for safety/compatibility fixes.

The first part: find . -maxdepth 1 -type d will return a list of all directories in the current working directory.  (Warning: -maxdepth is a GNU extension and might not be present in non-GNU versions of find.)  This is piped to...

The second part: while read -r dir; do (shown above as while read -r dir(newline)do) begins a while loop – as long as the pipe coming into the while is open (which is until the entire list of directories is sent), the read command will place the next line into the variable dir. Then it continues...

The third part: printf "%s:\t" "$dir" will print the string in $dir (which is holding one of the directory names) followed by a colon and a tab (but not a newline).

The fourth part: find "$dir" -type f makes a list of all the files inside the directory whose name is held in $dir. This list is sent to...

The fifth part: wc -l counts the number of lines that are sent into its standard input.

The final part: done simply ends the while loop.

So we get a list of all the directories in the current directory. For each of those directories, we generate a list of all the files in it so that we can count them all using wc -l. The result will look like:

./dir1: 234
./dir2: 11
./dir3: 2199
...
11
  • Always use read -r as plain read treats backslashes specially. Then echo -en "$dir:\t" will again mangle backslashes; a simple fix is to use printf '%s:\t' "$dir" instead. Next, $dir should be "$dir" (always use double quotes around variable substitutions). Commented Nov 18, 2010 at 1:40
  • modified per @Giles suggestions find -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" | wc -l; done Commented Nov 18, 2010 at 9:30
  • 3
    I'm adding sort -n -r -k2 to the end of this, for lots of directories, so that I know where the most usage is Commented Jan 25, 2011 at 10:45
  • The fourth part: find "$dir" makes a list of all the files inside the directory name held in "$dir". You forgot to add -type f to make it list files: find -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" -type f | wc -l; done Commented Jun 20, 2014 at 12:02
  • 1
    I'm not getting this to work on macOS Sierra 10.12.5. illegal option -- m in the find command. I changed it to find . -maxdepth ... and got it to work.
    – Jeff
    Commented Jul 24, 2017 at 13:28
85

Try find . -type f | wc -l, it will count of all the files in the current directory as well as all the files in subdirectories. Note that all directories will not be counted as files, only ordinary files do.

2
  • Just to be clear: Does it count files in the subdirectories of the subdirectories etc...?
    – Kvothe
    Commented Oct 8, 2021 at 16:34
  • 1
    @Kvothe Yes, recursively. :) Commented Oct 9, 2021 at 5:08
22

Here's a compilation of some useful listing commands (re-hashed based on previous users code):

List folders with file count:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type f | wc -l); printf "%4d : %s\n" $n "$dir"; done

List folders with non-zero file count:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type f | wc -l); if [ $n -gt 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

List folders with sub-folder count:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type d | wc -l); let n--; printf "%4d : %s\n" $n "$dir"; done

List folders with non-zero sub-folder count:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type d | wc -l); let n--; if [ $n -gt 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

List empty folders:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" | wc -l); let n--; if [ $n -eq 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

List non-empty folders with content count:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" | wc -l); let n--; if [ $n -gt 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done
3
  • And btw.. if you want to have the output of any of these list commands sorted by the item count .. pipe the command into a sort : "a-list-command" | sort -n Commented May 16, 2013 at 16:00
  • all those if's could be easily replaced with find [-not] -empty
    – vstepaniuk
    Commented Jan 14, 2020 at 5:56
  • @DolphinDream thanks, sort -n is good
    – netawater
    Commented Feb 8, 2022 at 13:51
16

Try:

find /path/to/start/at -type f -print | wc -l

as a starting point, or if you really only want to recurse through the subdirectories of a directory (and skip the files in that top level directory)

find `find /path/to/start/at -mindepth 1 -maxdepth 1 -type d -print` -type f -print | wc -l
6
  • +1 for something | wc -l ... word count is such a nice little tool
    – Johan
    Commented Nov 16, 2010 at 12:32
  • yeah but this only does 1 directory.... I'd like to get the count for all directories in a directory, and I don't want to run it seperately each time... of course I suppose I could use a loop... but I'm being lazy. Commented Nov 16, 2010 at 12:49
  • 1
    find works recursively through all sub directories by default. If you want it to work in multiple locations, you can specify all of them between find and -type. Commented Nov 16, 2010 at 14:33
  • that second one certainly doesn't work.... I tried it on /home . I got 698035 . I should see about 6 numbers. Commented Nov 16, 2010 at 21:02
  • It works for me - are you sure you only have 6 files under /home? I'd be 100% certain you don't.
    – Cry Havok
    Commented Nov 17, 2010 at 17:28
11

du --inodes

I'm not sure why no one (myself included) was aware of:

du --inodes
--inodes
      list inode usage information instead of block usage

I'm pretty sure this solves the OP's problem. I've started using it a lot to find out where all the junk in my huge drives is (and offload it to an older disk).

Further info

If you DON'T want to recurse (which can be useful in other situations), add

-S, --separate-dirs
5
  • 1
    a very nice option but not in all version of du :(
    – CervEd
    Commented Apr 25, 2021 at 10:40
  • I'm curious, which OS is that? I'm able to get it for Ubuntu and Mac OS X Commented Apr 25, 2021 at 18:29
  • not in freebsd :(
    – CervEd
    Commented Apr 25, 2021 at 19:07
  • I've never used BSD but did you try installing coreutils? I think that gives the GNU version of du. freshports.org/sysutils/coreutils Commented Apr 25, 2021 at 19:09
  • I might at some point but right now I'll probably make due with other solutions
    – CervEd
    Commented Apr 25, 2021 at 19:13
7

If you have ncdu installed (a must-have when you want to do some cleanup), simply type c to "Toggle display of child item counts". And C to "Sort by items".

2
  • 1
    lol, this must be the top-most accepted answer :)
    – x-yuri
    Commented Apr 25, 2019 at 13:17
  • While useful this does also count sub-directories as items.
    – MSpreij
    Commented Apr 24, 2023 at 13:53
4

The following solution counts the actual number of used inodes starting from current directory:

find . -print0 | xargs -0 -n 1 ls -id | cut -d' ' -f1 | sort -u | wc -l

To get the number of files of the same subset, use:

find . | wc -l

For solutions exploring only subdirectories, without taking into account files in current directory, you can refer to other answers.

1
  • 2
    Good idea taking hard links into account. Assuming GNU find, you don't need so many steps: find -printf '%i\n' | sort -u | wc -l. If you wanted to be portable, you'd need find . -exec ls -id {} + | cut … instead. Commented Nov 19, 2010 at 20:24
2

Give this a try:

find -type d -print0 | xargs -0 -I {} sh -c 'printf "%s\t%s\n" "$(find "{}" -maxdepth 1 -type f | wc -l)" "{}"'

It should work fine unless filenames include newlines.

2
  • way too recursive... I only want to see the top level, where it totals everything underneath it. totaled... this ends up printing every directory. Commented Nov 16, 2010 at 21:05
  • @xenoterracide: Try adding -maxdepth 1 immediately after the first find. If you want to include the number of subdirectories in your count, remove the -type f at the end (that should have really been ! -type d anyway, so that all non-directory files would have been included). Commented Nov 16, 2010 at 23:15
2

OS X 10.6 chokes on the command in the accepted answer, because it doesn't specify a path for find. Instead use:

find . -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" -type f | wc -l; done
0
2

I know I'm late to the party, but I believe this pure bash (or other shell which accept double star glob) solution could be much faster in some situations:

shopt -s globstar    # to enable ** glob in bash
for dir in */; do a=( "$dir"/**/* ); printf "%s\t%s\n" "$dir:" "${#a[*]}"; done

output:

d1/:    302
d2/:    24
d3/:    640
...
0

Use this recursive function to list total files in a directory recursively, up to a certain depth (it counts files and directories from all depths, but show print total count up to the max_depth):

#!/bin/bash
# set -x

export max_depth="2"
export found_files="/tmp/found_files.txt"

function get_all_the_files()
{
    depth="$1";
    base_directory="$2";

    if [[ "$depth" -ge "$max_depth" ]];
    then
        return;
    fi

    find "$base_directory" -maxdepth 1 -type d | while read -r inner_directory
    do
        printf "%s\t%s\n" "$(find "$inner_directory" | wc -l)" "$inner_directory" | tee -a "$found_files";
        if [[ "w$(realpath "$base_directory")" != "w$(realpath "$inner_directory")" ]];
        then
            get_all_the_files "$(( depth + 1 ))" "$inner_directory";
        fi;
    done;
}

rm -f "$found_files"
get_all_the_files 0 /tmp/

printf '\nFinished searching files, sorting all:\n'
sort --version-sort "$found_files"
0

Inside the folder (directory) you want to count (cd /my/dir) you can do the following:

  1. To count all folders and files: find . | wc -l
  2. To count only folders (directories): find . -type d | wc -l
  3. To count only files: find . -type f | wc -l

This way you are able to verify that: folders (2) + files (3) = total (1)


Some explanation:

  • The command find . will print each of all the folders (directories) and files line by line.
    • The parameter: -type d says to print only directories (folders)
    • The parameter: -type f says to print only files.
  • The command wc -l should mean something like: word count with the parameter: lines.

You must log in to answer this question.

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