Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This question already has an answer here:

If parsing the output of ls is dangerous because it can break on some funky characters (spaces, \n, ... ), what's the best way to know the number of files in a directory?

I usualy rely on find to avoid this parsing, but similarly, find mydir | wc -l will break for the same reasons.

I'm working on Solaris right now, but I'm looking for a answer as portable across different unices and different shells as possible.

share|improve this question

marked as duplicate by Gilles, Braiam, slm Oct 17 '14 at 5:55

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

I'm not sure it's a duplicate, am I missing something? –  rahmu Oct 17 '14 at 11:32

6 Answers 6

up vote 13 down vote accepted

How about this trick?

find . -maxdepth 1 -exec echo \; | wc -l

As portable as find and wc.

share|improve this answer
This doesn't work (it displays n+1 files on my Debian system). It also doesn't filter for regular files. –  Chris Down Dec 23 '11 at 13:35
I just gave a generic example. It does work, but how it works depends on how you adapt the find command to your specific needs. Yes, this one includes all the directories, including . (which might be why you see the result as n+1). –  rozcietrzewiacz Dec 23 '11 at 15:35
I like this trick, very clever; but I'm surprised there's no simple straightforward way to do that! –  rahmu Dec 23 '11 at 16:11
@ChrisDown the OP doesn't specify filtering for regular files, asks for number of files in a directory. To get rid of the n+1 issue, use find . -maxdepth 1 ! -name . -exec echo \; | wc -l; some older versions of find do not have -not. –  Arcege Dec 23 '11 at 16:50

With bash, without external utilities, nor loops:

shopt -s dotglob
echo ${#files[@]}

In ksh, replace shopt -s dotglob by FIGNORE=.?(.). In zsh, replace it by setopt glob_dots, or remove the shopt call and use files=(*(D)). (Or just drop the line if you don't want to include dot files.) Portably, if you don't care about dot files:

set -- *
echo $#

If you do want to include dot files:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c
share|improve this answer


ls -b1A | wc -l

The -b will have non-printable characters, -A will show all files except . and .. and one per line (the default on a pipe, but good to be explicit).

As long as we're including higher-level scripting languages, here's a one-liner in Python:

python -c 'import os; print len(os.listdir(os.sep))'

Or with full 'find':

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'
share|improve this answer

Yoc can use such construction:

I=0; for i in * ; do ((I++)); done ; echo $I

But I'm afraid, you can cath error like Argument list too long. in case you have too many files in directory. However I tested it on directory with 10 billion files, and it worked well.

share|improve this answer
THis won't work for hidden files either unless the shell is configured to expand those with *. –  Lekensteyn Dec 23 '11 at 11:53
gnu find . -maxdepth 1 -type f | wc -l –  Nikhil Mulley Dec 23 '11 at 14:41
@Rush: this command should never raise "arg list too long". That only happens with external command (so never with for. –  enzotib Dec 23 '11 at 16:16

Have you considered perl, which should be relatively portable?

Something like:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter

find(\&wanted, @directories_to_search);
print "$counter\n";
share|improve this answer

Try this => Using ls with -i ( for node number ) & -F (appends directory name with '/' ) options.

ls -ilF | egrep -v '/' | wc -l
share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.