"ls -lh" reports total size less than sum of individual sizes

It will happen if you have sparse files:

$ mkdir test; cd test
$ truncate -s 1000000000 file-with-zeroes
$ ls -l
total 0
-rw-r--r-- 1 gim gim 1000000000 03-08 22:18 file-with-zeroes

A sparse file is a file which has not been populated with filesystem blocks (or only partially). When you read a non-populated zone of a sparse file you will obtain zeros. Such blank zones do not require actual disk space, and the 'total' reported by ls corresponds to the disk space occupied by the files (just like du).


Please note that the output given by ls -l and du has a subtle but very important difference. Try this:

dd if=/dev/urandom of=aaa bs=1024 count=1

Now

ls -l aaa
-rw-r--r-- 1 abc abc 1024 2012-03-08 15:45 aaa

Whereas

du -h aaa
4.0K    aaa

This is because the filesystem allocates size in chunks of 4096 ( on my linux box). It is called IO Block. You can see this by:

    stat aaa
  File: `aaa'
  Size: 1024        Blocks: 8          IO Block: 4096   regular file

The currently accepted answer is absolutely correct, just if you want to see apparent size, you can use:

du --apparent-size

print apparent sizes, rather than disk usage; although the apparent size is usually smaller, it may be larger due to holes in ('sparse') files, internal fragmentation, indirect blocks, and the like