10

I'm working on a little util tool written in bash that gives me some information about a game server on Linux. For that reason I need a possibility to display the size of the file contents.

I'm doing that right now by using this:

du -Lshc *

It works almost perfect! The only flaw is that it displays stuff like this:

21G     backups
22G     server
8.0K    start.sh
151M    world.zip
43G     total

This is fine but I want more digits. Meaning it should look like that:

21.587G     backups
22.124G     server
8.089K      start.sh
151.198M    world.zip
43.436G     total

Is there a possiblility to do that?

I wouldn't mind using a complex command since I use it in a .sh file so I won't type it by hand every time.

Jawa
  • 3,619
  • 13
  • 31
  • 36
BrainStone
  • 400
  • 2
  • 7
  • 25

2 Answers2

9
du -Lsbc * | awk '
    function hr(bytes) {
        hum[1024**4]="TiB";
        hum[1024**3]="GiB";
        hum[1024**2]="MiB";
        hum[1024]="kiB";
        for (x = 1024**4; x >= 1024; x /= 1024) {
            if (bytes >= x) {
                return sprintf("%8.3f %s", bytes/x, hum[x]);
            }
        }
        return sprintf("%4d     B", bytes);
    }

    {
        print hr($1) "\t" $2
    }
'

awk-function based on this.

One could probably make the output look a bit nicer by piping it through column or left-padding it with spaces.

Edit: Added the left-padding.

Also, to sort the list: du -Lsbc * | sort -n | awk and then the awk-script.

BrainStone
  • 400
  • 2
  • 7
  • 25
n.st
  • 1,908
  • 1
  • 17
  • 30
  • This is almost perfect. It only has a little issue if the file size is 0. Then no number is displayed. Another thing is that there are decimal places if the unit is B (Meaning it looks like `108.000B`. Which is some kind of akward.) But thank you anyways! – BrainStone Aug 18 '13 at 13:06
-1

Here is my bash implementation using the code of @n.st

hr() {
    bytes=$1
    hum[1024**4]="TiB";
    hum[1024**3]="GiB";
    hum[1024**2]="MiB";
    hum[1024]="kiB";
    x=0
    for ((x = 1024**4; $x >= 1024; x = ($x/1024) ))
    do
        if [ "$bytes" -ge "$x" ]; then
            $(printf "%8.3f %s" $( echo "$bytes $x" | awk '{printf "%.2f \n", $1/$2}' ) ${hum[$x]});
            return 0;
        fi
    done
    echo $(printf "%4d     B" $bytes);
}

Try

echo $(hr 1024);
echo $(hr 4096);
echo $(hr $((1024*500)) );
echo $(hr $((1024*8000)) );
echo $(hr $((1024*1024*500)) );
echo $(hr $((1024*1024*1024*500)) );
echo $(hr 2127780017);

Output

1.000 kiB
4.000 kiB
500.000 kiB
7.810 MiB
500.000 MiB
500.000 GiB
1.980 GiB
  • 2
    The question was about making `du` output in that format. Not creating a function/script that takes the size as a parameter. You couldn’t even pipe `du` into it. – BrainStone Aug 08 '18 at 15:08
  • @BrainStone Yes, who knows maybe someone will need my implementation some day. – William Desportes Aug 08 '18 at 15:14
  • `awk` is about as portable as `bash` – BrainStone Aug 08 '18 at 15:20
  • 1
    I tried to put this into a `bash` script so I could call it at the command-line and supply a directory to it. I tried modifying the code so that it would take in a directory instead, but I was not successful in doing so. It would be extremely helpful if you actually modified this so that it could take in a directory, which would then find the size of the directory then call your function. As is, this function doesn't directly answer the question and I find it not useful. – rayryeng Apr 03 '23 at 14:34