Every directory on a Unix system (and probably every other system too) contains at least two directory entries. These are .
(current directory) and ..
(parent directory). In the case of the root directory, these point to the same place, but with any other directory, they are different. You can see this for yourself using the stat
, pwd
and cd
commands (on Linux):
$ cd /
$ stat . .. bin sbin | grep Inode
Device: 802h/2050d Inode: 2 Links: 27
Device: 802h/2050d Inode: 2 Links: 27
Device: 802h/2050d Inode: 548865 Links: 2
Device: 802h/2050d Inode: 2670593 Links: 2
$ pwd
/
$ cd ..
$ pwd
/
$
Notice that bin
and sbin
each has two links to it. One is the directory entry in the root directory, and the other is the .
entry inside that directory.
Using ls
with a pipe to wc -l
is a simple trick to count the number of lines in ls' output. The assumption is that each file or directory will occupy exactly one line in the output. GNU ls will, when the output is a non-terminal, do this automatically; others might need the -1
option to turn on the behavior explicitly. wc -l
simply counts and outputs the number of lines (-l
) in its input.
The problem with that approach is that in Linux and on the file systems traditionally used on Linux, file and directory names (they are really one and the same in this regard) are allowed to contain newline characters. In the presence of those, either method falls apart -- those entries will be counted as two or more entries when in reality they are one.
As long as you are using GNU ls, have no directory entries with names containing newline characters, and have no odd aliases for ls
(for example, ls -a
), both will output the count of files and directories in the current (or specified) directory. For most people, this is good enough, but it is not valid in the general case.
If you need to handle unusual characters (primarily newlines) in directory entry names properly, I suggest using ls's -b
option to escape them. ls -1bA
will print each directory entry name on its own line, escape unusual characters (so each directory entry will be seen as one), including any dotfiles and -directories. Tack on wc -l
for a complete command line of ls -1bA | wc -l
which will report the number of files and directories in the current directory (but ignore .
and ..
; that's the difference between -a
and -A
), but not descend into any subdirectories. If you don't want any dotfiles to be counted towards the total, simply omit the -A
parameter to ls
.