Using ls to list directories and their total sizes

Viewed 1036067

Is it possible to use ls in Unix to list the total size of a sub-directory and all its contents as opposed to the usual 4K that (I assume) is just the directory file itself?

total 12K
drwxrwxr-x  6 *** *** 4.0K 2009-06-19 10:10 branches
drwxrwxr-x 13 *** *** 4.0K 2009-06-19 10:52 tags
drwxrwxr-x 16 *** *** 4.0K 2009-06-19 10:02 trunk

After scouring the man pages I'm coming up empty.

29 Answers

Try something like:

du -sh *

short version of:

du --summarize --human-readable *

Explanation:

du: Disk Usage

-s: Display a summary for each specified file. (Equivalent to -d 0)

-h: "Human-readable" output. Use unit suffixes: Byte, Kibibyte (KiB), Mebibyte (MiB), Gibibyte (GiB), Tebibyte (TiB) and Pebibyte (PiB). (BASE2)

du -sh * | sort -h

This will be displayed in human readable format.

The command you want is 'du -sk' du = "disk usage"

The -k flag gives you output in kilobytes, rather than the du default of disk sectors (512-byte blocks).

The -s flag will only list things in the top level directory (i.e., the current directory, by default, or the directory specified on the command line). It's odd that du has the opposite behavior of ls in this regard. By default du will recursively give you the disk usage of each sub-directory. In contrast, ls will only give list files in the specified directory. (ls -R gives you recursive behavior.)

ncdu (ncurses du)

This awesome CLI utility allows you to easily find the large files and directories (recursive total size) interactively.

For example, from inside the root of a well known open source project we do:

sudo apt install ncdu
ncdu

The outcome its:

enter image description here

Then, I enter down and right on my keyboard to go into the /drivers folder, and I see:

enter image description here

ncdu only calculates file sizes recursively once at startup for the entire tree, so it is efficient.

"Total disk usage" vs "Apparent size" is analogous to du, and I have explained it at: why is the output of `du` often so different from `du -b`

Project homepage: https://dev.yorhel.nl/ncdu

Related questions:

Tested in Ubuntu 16.04.

Ubuntu list root

You likely want:

ncdu --exclude-kernfs -x /

where:

  • -x stops crossing of filesystem barriers
  • --exclude-kernfs skips special filesystems like /sys

MacOS 10.15.5 list root

To properly list root / on that system, I also needed --exclude-firmlinks, e.g.:

brew install ncdu
cd /
ncdu --exclude-firmlinks

otherwise it seemed to go into some link infinite loop, likely due to: https://www.swiftforensics.com/2019/10/macos-1015-volumes-firmlink-magic.html

The things we learn for love.

ncdu non-interactive usage

Another cool feature of ncdu is that you can first dump the sizes in a JSON format, and later reuse them.

For example, to generate the file run:

ncdu -o ncdu.json

and then examine it interactively with:

ncdu -f ncdu.json

This is very useful if you are dealing with a very large and slow filesystem like NFS.

This way, you can first export only once, which can take hours, and then explore the files, quit, explore again, etc.

The output format is just JSON, so it is easy to reuse it with other programs as well, e.g.:

ncdu -o -  | python -m json.tool | less

reveals a simple directory tree data structure:

[
    1,
    0,
    {
        "progname": "ncdu",
        "progver": "1.12",
        "timestamp": 1562151680
    },
    [
        {
            "asize": 4096,
            "dev": 2065,
            "dsize": 4096,
            "ino": 9838037,
            "name": "/work/linux-kernel-module-cheat/submodules/linux"
        },
        {
            "asize": 1513,
            "dsize": 4096,
            "ino": 9856660,
            "name": "Kbuild"
        },
        [
            {
                "asize": 4096,
                "dsize": 4096,
                "ino": 10101519,
                "name": "net"
            },
            [
                {
                    "asize": 4096,
                    "dsize": 4096,
                    "ino": 11417591,
                    "name": "l2tp"
                },
                {
                    "asize": 48173,
                    "dsize": 49152,
                    "ino": 11418744,
                    "name": "l2tp_core.c"
                },

Tested in Ubuntu 18.04.

I always use du -sk (-k flag showing file size in kilobytes) instead.

If you want more control over the size that you want to list the directories over, you can use the threshold (-t) switch as in:

$ du -ht 1000000000 | sort --reverse

du - disk usage
h - human readable format
t - threshold size

Here, we want to list all directories which are greater than 1GB in size.

$ du -ht 1G | sort --reverse

Explanation:

Units that are described in wiki follows:

K, M, G, T, P, E, Z, Y (powers of 1024) or
KB, MB, GB, TB, PB, EB, ZB, YB (powers of 1000).

Ordered list of folders and files (descendant order, according to size) in a directory:

du -skh * | sort -hr

Including hidden files:

du -skh .??* * | sort -hr

Explanation:

  • The command shows bigger files/folders first.
  • It works with hidden (starting with dot) files/folders.
  • It shows human-readable sizes (GB, MB, etc...).

Note. Other answers contain most of these options but scattered along different answers and none here explore how to easily include hidden files/folders.

sudo du -hsx 2>/dev/null *

0       bin
4.0K    boot
0       dev
9.0M    etc
6.5M    home
824K    init
0       lib
0       lib32
0       lib64
0       libx32
16K     lost+found
4.0K    media
4.0K    mnt
4.0K    opt
0       proc
61M     root
36K     run
0       sbin
4.0K    srv
0       sys
4.0K    tmp
2.2G    usr
4.9G    var

place in init script like .bashrc ... adjust def as needed.

duh() {
  # shows disk utilization for a path and depth level
  path="${1:-$PWD}"
  level="${2:-0}"
  du "$path" -h --max-depth="$level"
}

It is important to note here that du gives you disk usage. Different machines can use different block sizes, so on one machine a block could be 4096 bytes and another machine could contain block sizes of 2048. If I put 10 1 byte files in a machine using 4096 bytes blocks and 10 1 byte file in a machine using 2048 bytes blocks, du -h would report ~40k and ~20k respectively.

If you want to know the size of all the files in a directory, for each directory you can do something like:

for x in ./*;
do
    if [[ -f "$x" ]]; then
        ls -al "$x"
    fi
done | awk '{print $6}' | awk '{s+=$1}END{print s}'

This would give you the total size of all the files in a directory.

find . -maxdepth 1 -exec du --apparent-size --max-depth=0 --null '{}' ';' |\
  sort -k1 -nr --zero-terminated |\
  cut -f2 --zero-terminated |\
  xargs --null -n 1 du -h --apparent-size --max-depth=0

Features:

  • Since Linux filenames can have newlines or blank spaces, we use null character to delimit file/directory names.
  • We sort the files/directories by their size.
  • We use --apparent-size with du to get a behavior similar to ls.

Retrieve only the size in bytes, from ls.

ls -ltr | head -n1 | cut -d' ' -f2
Related