Is it possible to add a thousands comma separator to the output of the Linux "df" command

df command gives me good information, and I love to see it in KB unit. But I need a thousands separator (aka: a comma) every 3 digits because the numbers will be always huge.

ex> df
Filesystem        1K-blocks        Used Available Use% Mounted on
rootfs             20157076     2982212  16970148  15% /
none                      4           0         4   0% /sys/fs/cgroup
/dev/sda2       27206836656 27189604228  17113644 100% /volume1

iwant> df
Filesystem          1K-blocks           Used   Available  Use% Mounted on
rootfs             20,157,076      2,982,212  169,70,148 14.8% /
none                        4              0           4    0% /sys/fs/cgroup
/dev/sda2      27,206,836,656 27,189,604,228  17,113,644  100% /volume1

I hate the -h (human readable) option because it will make everything illogical. Especially unit bytes will be different between every number. I want every number on the same unit.

All I need is a thousands separator… Is there any option for it when using df?


Solution 1:

You can use awk to format the numbers with %'d then use column to format the table

$ df | LC_ALL=en_US.UTF-8 awk '{
if (NR == 1) { print gensub(/ +/, "\t", "g") } else {
  printf("%s\t%'"'"'d\t%'"'"'d\t%'"'"'d\t%d\t%s\n", $1, $2, $3, $4, $5, $6)
} }' | column -t -R 2,3,4,5 -s$'\t'
Filesystem   1K-blocks        Used   Available  Use%  Mounted                 on
dev          1,002,104           0   1,002,104     0  /dev
run          1,011,880       1,060   1,010,820     1  /run
/dev/sda2   36,285,808  17,358,124  17,054,752    51  /
tmpfs        1,011,880           0   1,011,880     0  /dev/shm
tmpfs        1,011,880           0   1,011,880     0  /sys/fs/cgroup
tmpfs        1,011,880       8,300   1,003,580     1  /tmp
/dev/sda1      306,584         264     306,320     1  /boot/efi
tmpfs          202,376          28     202,348     1  /run/user/1000
/dev/sr0        58,122      58,122           0   100  /run/media/mypc/myfolder

By setting the locale with LC_ALL you can change to any thousand formats available out there. You can also remove the -R option if you don't want to right-align the numbers or your column version doesn't have that option (like the default one on Ubuntu)

If you get the function gensub never defined error then it's because of this bug which can be solved by installing gawk. Alternatively change the delimiter to space instead of tab:

df | LC_ALL=en_US.UTF-8 awk '{
if (NR == 1) { print } else {
  printf("%s\t%'"'"'d\t%'"'"'d\t%'"'"'d\t%d\t%s\n", $1, $2, $3, $4, $5, $6)
} }' | column -t

If you want to get the KB value you'll need to divide the corresponding columns

df | LC_ALL=en_US.UTF-8 awk -v K=1024 '{
    if (NR == 1) { print gensub(/ +/, "\t", "g") }
    else { printf("%s\t%'"'"'d\t%'"'"'d\t%'"'"'d\t%d\t%s\n",
                  $1, $2/K, $3/K, $4/K, $5, $6) } }
' | column -t -R 2,3,4,5 -s$'\t'

If you want to get a floating-point value just change %d to %f

df | LC_ALL=en_US.UTF-8 awk -v K=1024 '{
        if (NR == 1) { print gensub(/ +/, "\t", "g") }
        else { printf("%s\t%'"'"'0.2f\t%'"'"'0.2f\t%'"'"'0.2f\t%d\t%s\n",
                      $1, $2/K, $3/K, $4/K, $5, $6) } }
' | column -t -R 2,3,4,5 -s$'\t'

Of course you can also align the columns directly from awk with the field width option like printf "%-10d %10d\n", $1, $2 without needing column but you'll have to reserve enough space for each column

Solution 2:

Because there is no solution yet, I tried using sed like below:

df | sed -r ':L;s=\b([0-9]+)([0-9]{3})\b=\1,\2=g;t L'

It works, but result with multi-lines doesn't looks good, because of bad alignment.

But I sadly have to use this line for a while.