how to count files, links and sub-directories in a directory in linux
Often times it is natural for a directory to grow large in terms of the files and sub-directories in them. Although there is really no technical limitations for the amount files or sub-directories you can have in most modern Linux systems, you still might want to find the count of files and directories you have.
The easiest and quickest is to use the ls command and count the number of lines that it prints out using the wc command. You can find the simplest of examples below.
bash$ ls -1 | wc -l
However, this does have its limitations. This will print out the total count, including the links, sub-directories and files and only goes one level down. This will not include sub-directories more than one level deep or files in those directories. Having said that, there is an argument -R for ls that recurses the folders and prints out all the files. The output however prints out sub-directory names as well directory name which results in double counting. This is good enough for a estimate but is not the exact count.
In order to have some flexibility in differentiating between file types and depths, you will need to use the find command.
bash$ ls -1R | wc -l
For the sake of clarity, it is possible to run the output through other filters such as grep to filter out just the files, etc. This does get a little complicated as more filters are added, and I prefer the find command in most cases, which is usually simpler.
For the rest of the article, let us assume that the folder we have is named music /and we want to find the files, links and sub-directories inside this folder.
Find Number of Files
In order to find only the files, we have to specify the type f in find command. You can also specify the maximum depth that you want to traverse, by using the maxdepth of 1 and file type f, we can count files in the current directory, without traversing into the sub folders.
bash$ find music/ -maxdepth 1 -type f | wc -l
In order to find all files, including those in the sub-folders, we will need to remove the maxdepth option as below.
bash$ find music/ -type f | wc -l
Using the printf option with find will execute this slightly faster especially if you have tons of files. We will follow this format for the rest of the post.
bash$ find music/ -type f -printf . | wc -c
Here, we are just going to print a dot (.) for every file, and then we will just count the total number of dots. The -c option of wc command will count the total number of characters. Printing out the entire path for each file and then counting the lines is an overkill if we are just interested in the total count.
Find Number of Links
If you just want to find the symbolic links and just the symbolic links in the folder, the -type option in find command is l to denote links. The following command will count all symbolic links in all folders.
bash$ find music/ -type l -printf . | wc -c
Find Number of Sub-Directories
If you want to count only the sub-directories then again change the type to d in the find command to match only the directories. The below example will count all the directories and sub-directories in the music/ folder.
bash$ find music/ -type d -printf . | wc -c
There is a small issue when counting directories using find command above, it will also count the (current or top-level) directory as well (in this case music/). This means that the directory count will be one more than what you expect, if you are looking for just the sub-folders. If you want to avoid that, then you can do the following
bash$ find music/* -type d -printf . | wc -c
It is also possible to combine the file types. If you want to just count files and links, but not the sub-directories then you can do it with the command below. The same goes for other files type combinations.
bash$ find music/ -type f -o -type l -printf . | wc -c
Print All Together
Now, we can put all of these together to print out each of them separately. If you intend to do this routinely, it might be worthwhile to create a shell script that can be executed repeatedly. You can then make the folder name (eg. music/) and the max-depth values as command line arguments to the script.
In order to do this, we will go into each directory, and then count the files, links and sub-directories in each of them. First, let us find only files that are one level deep which means we will not compute files inside the sub-folders in each of these directories.
find music/ -maxdepth 1 -type d |while read dir;do counttotal=$(find "$dir" -maxdepth 1 -printf . | wc -c); countdir=$(find "$dir" -maxdepth 1 -type d -printf . |wc -c); countfile=$(find "$dir" -maxdepth 1 -type f -printf . |wc -c); countlink=$(find "$dir" -maxdepth 1 -type l -printf . |wc -c); echo "[Total:$counttotal][Dir:$countdir;File:$countfile;Links:$countlink] : $dir "; done
Now the above script will only print counts for the folders that are one level deep. If you like to print counts for all the directories and sub-directories then modify the script above to remove the maxdepth argument from the first find. In order to count files, irrespective of the depth remove the maxdepth argument from the other find commands in the script but keep the maxdepth in the first find.
Now, let us print the counts for all directories as above, but count all the files and sub-directories at all depths. Remember that this will count files in the context of the folder, which means it is quite possible that a single file will counted towards different folders depending on how deep the file is in the structure.
find music/ -type d |while read dir;do counttotal=$(find "$dir" -printf . | wc -c); countdir=$(find "$dir" -type d -printf . |wc -c); countfile=$(find "$dir" -type f -printf . |wc -c); countlink=$(find "$dir" -type l -printf . |wc -c); echo "[Total:$counttotal][Dir:$countdir;File:$countfile;Links:$countlink] : $dir "; done
Another option is the tree command. This however does not come standard in many systems and will need to installed. The tree command provides some very useful options to display different file types much more easily.