I learned that 'ls | wc -l' command prints number of files in the current directory, but it includes all files and directories. Can I do the same task only for pure files excluding directories?
-
2Possibly a dupe of script to count files in a directory – Kusalananda Apr 05 '21 at 07:42
3 Answers
directory is just one of many types of files. Other types include symbolic link, fifo, device, regular, socket...
In the output of ls -n
, the first character indicates the type. d
for directory, -
for regular, l
for symlink, so you could do:
LC_ALL=C ls -Aqn | LC_ALL=C grep -c '^-' # regular files only
LC_ALL=C ls -Aqn | LC_ALL=C grep -vc '^d' # anything but directory
(remove the -A
option if you don't want to count hidden files).
You could also do the check after symlink resolution,
LC_ALL=C ls -LAqn | LC_ALL=C grep -c '^-' # regular files or symlinks to regulars
LC_ALL=C ls -LAqn | LC_ALL=C grep -vc '^d' # anything but directory and symlinks to dirs.
With the zsh
shell, you can also do it using globbing:
(){print $#} *(NDoN.) # regular
(){print $#} *(NDoN^/) # non-directories
After symlink resolution (adding the -
glob qualifier):
(){print $#} *(NDoN-.) # regular
(){print $#} *(NDoN-^/) # non-directories
(remove the D
qualifier if you don't want to count hidden files).
oN
is to disable the sorting of the file list as an optimisation as we don't care about the order. The GNU implementation of ls
has a -U
option for that.
In any case, your ls | wc -l
is wrong as it counts the number of newline characters used by ls
to delimit the file names (so one per file), but also the newline characters in the names of the file (it also omits hidden files). Using the -q
option works around it as it causes newline characters in filenames to be rendered as ?
.

- 544,893
I would normally use:
find . -maxdepth 1 -type f | wc -l
Beware that:
- this also count file names starting with
.
- only looks at regular files (not fifo, symlinks etc)

- 35,514
-
1That counts the number of lines in the file names, not the number of files. Use
find . -maxdepth 1 -type f | LC_ALL=C grep -c /
to count the number of regular files. Also not that-maxdepth
is a non-standard GNU extension. Usefind . ! -name . -prune -type f | LC_ALL=C grep -c /
posixly (equivalent of-mindepth 1 -maxdepth 1
) – Stéphane Chazelas Apr 05 '21 at 08:19 -
that should be
| LC_ALL=C grep -c '^\./'
- otherwise you'll still count partial path-names with vertical spaces like linefeeds in directory names earlier in the path, like./foo<LF>bar/bar<LF>foo/filename
. Actually, even that regex can still be fooled by things like./foo<LF>./bar/filename
– cas Apr 05 '21 at 12:50 -
so use
find
with-print0
andgrep -z -c ...
(GNU grep, maybe others too, i can't remember right now). GNUwc
also supports--files0-from=-
for NUL-separated stdin. – cas Apr 05 '21 at 12:56
I am not yet able to post a comment but here is a bash-specific solution. It is not as succinct but might feel cleaner without the use of grep
.
Since you used just ls
I assume that you do not need hidden files.
i=0
for f in *
do
[[ -f "$f" ]] && let "i++"
done
echo $i
Or combined into a one-liner, i=0; for f in *; do [[ -f "$f" ]] && let "i++"; done; echo $i

- 72
-
Note that it counts regular files and symlinks to regular files, excluding hidden ones, so would be the equivalent of
zsh
's(){print $#} *(NoN-.)
orls -Lqn | LC_ALL=C grep -c '^-'
– Stéphane Chazelas Apr 05 '21 at 08:11