What is the Best Way to Count Files in a Directory?

  • HOME
  • >
  • LINUX
  • >
  • What is the Best Way to Count Files in a Directory?
Last Updated: 
subscribe to my newsletter

There are multiple ways on how to count the number of files in a directory on Linux. Some are less reliable than others and may even lead to an inacurate count of files. This post covers the pitfalls and best practices for three different approaches using ls, find, and the bash shell using globbing and a bash array.

How to count files using the ls and wc commands?

Most solutions you will find online will try to parse a ls command output which is piped through the wc command line, sometimes adding a grep in the mix. A common example is ls -la | wc -l. This approach is not reliable and should be avoided.

Besides the two forked processes for ls and wc, the ls output should never be parsed as a file name may contain a newline character which would lead to bad results when using ls and wc. In that example, the count will also be incorrect as it would include the . (current directory) and .. (parent directory) references.

A better version would be to use ls -1bA | wc -l which would skip the . and .. from the ls output, escape non-printable characters, and force the output to be one entry per line.

[me@linux ~]$ ls -a tmp/
.     ..    .one  file1 file2
[me@linux ~]$ ls -a tmp/ | wc -l
5
[me@linux ~]$ ls -1bA tmp/*
tmp/.one
tmp/file1
tmp/file2
[me@linux ~]$ ls -1bA | wc -l
3

How to count files using the find and wc commands?

Another solution, similar to the previous one, is to use the find command line with wc, example: find tmp/ -type f | wc -l.

This approach will suffer from a similar pitfall as the ls one since file names may contain non-printable characters, including newlines. The output may not be reliably parsed. To overcome this, we can use the printf option of the GNU find utility. Note, that this is not a standard POSIX option.

By using printf we can skip the filename output and replace it with a dot (or any other single character) for each file found, then only count the total characters using wc -c, example: find tmp -type f -printf '.' | wc -c.

👉 To install GNU Find on macOS, you can use the homebrew package manager with the command brew install findutils. The find command will be installed as gfind by default.

[me@linux ~]$ find tmp -type f
tmp/file2
tmp/file1
tmp/.one
[me@linux ~]$ find tmp -type f | wc -l
3
[me@linux ~]$ find tmp -type f -printf '.'
...
[me@linux ~]$ find tmp -type f -printf '.' | wc -c
3

How to count files using the Bash shell only?

You don't need to use other command-line tools to count the number of files in a directory in bash. Instead of the previous solutions, without extra fork(), you can use bash globbing with the nullglob and dotglob options with a bash array and optionally a bash if statement.

  • The nullglob option will expand to a null string (empty value) when no files match the filename patterns.
  • The dotglob option is used to also list hidden files starting with a dot (.). You can skip this option if you only want to count files that don't start with a dot.

Make sure to set (using shopt -s nullglob dotglob) and unset (using shopt -u nullglob dotglob) the options before and after your test as it may impact the rest of your script behavior, especially with the nullglob option.

[me@linux ~]$ shopt -s nullglob dotglob
[me@linux ~]$ matched_files=(tmp/*)
[me@linux ~]$ if ! (( ${#matched_files[*]} )); then
  echo "Directory is empty"
else
  echo "The directory contains ${#matched_files[@]} items which include files, symlink, directories, etc."
fi

# Example Output: The directory contains 3 items which include files, symlink, directories, etc.
[me@linux ~]$ shopt -u nullglob dotglob

You can optionally set the shopt in a subshell to ensure that the rest of your script is not impacted, at the cost of an additional fork(). Below is an example with a bash subshell to check if a directory is empty. Remember that you cannot access variables defined in a subshell, so the use cases may be limited or less readable.

[me@linux ~]$ if (shopt -s nullglob dotglob; files=(tmp/*); ((${#files[@]}))); then
  echo "The directory is not empty";
fi
The directory is not empty
Related linux posts that you may like...
How To Create Simple Menu with the Shell Select Loop?
The select loop is not a regular shell loop. It can be used in Bash to generate a simple menu from which a user can select numbered options.
What is the Right Way to Loop in Bash?
Looping over a list of numbers or words is a building block in shell scripts. Learn how to write Bash loops, including for loop, while loop, and until loop.
5 Mistakes To Avoid For Writing High-Quality Bash Comments
Adding comments in your Bash scripts is necessary to ensure maintainability over time. This post covers 5 Bash comments mistakes to avoid in your shell scripts.
How to Script Powerful Bash If Statement?
Learn how to script a Bash If statement with the then, else, and else if / elif clauses. This post covers the Bash conditional expressions, and how to avoid common pitfalls when using the Bash If statement.