Getting filesystem disk free info

Bob Proulx bob at proulx.com
Tue Jan 11 23:07:57 MST 2022


Continuing on with some follow-up from the meet tonight...

Here is a little example that illustrates how I would get the df
output percent used data and also how I would write a script for
debugging.

    #!/bin/sh
    used=$(df / | awk '$NF=="/"{print$5}')
    : "debug: case $used in"
    case $used in
        [0-9]*%) : "debug: pattern matches [0-9]*% okay" ;;
        *) echo "Error: df /: failed: Use%=$used" 1>&2; exit 1 ;;
    esac
    : "debug: Remove trailing % from $used"
    used=${used%"%"}
    echo used=$used

Let's run it.

    $ /tmp/trial.sh
    used=67

That's correct but let's see what the debug tracing of it would look
like using sh -x on it.

    $ sh -x /tmp/trial.sh
    + df /
    + awk $NF=="/"{print$5}
    + used=67%
    + : debug: case 67% in
    + : debug: pattern matches [0-9]*% okay
    + : debug: Remove trailing % from 67%
    + used=67
    + echo used=67
    used=67

When -x is in effect it will print out shell commands as they are
executed.  But purely internal actions are silent.  Purely internal
means things like "case $var in" and the suffix removal actions such
as ${used%"%"} which is otherwise silent.  Therefore I leave a trail
of other noop commands with hints which are only emitted when command
tracing is on.

The ":" command is a shell builtin.  Let's ask bash about it.

    $ type :
    : is a shell builtin

    $ help :
    :: :
        Null command.
        
        No effect; the command does nothing.
        
        Exit Status:
        Always succeeds.

It's almost an alias for true.  Almost.  Let's not worry about the
differences right now.  It's always succeeds.  And it can have option
arguments.  Which are printed out when command tracing is on.  Making
it look like an active comment.  But beware that shell redirections
and other meta-characters are active unless quoted.  Therefore I
usually quote everything : "debug: A < B" and so forth to avoid any
problems with shell meta-characters there.  Also using a : like that
looks almost comment like and not too unpleasant in the code.  Just
remember that it is a true noop and is getting executed.  But since it
is a builtin to the shell it is very fast, as are all of the builtins.

When running something external it's always good to check that it
worked.  In this case I am a little slack because I know the field
will end with a % and if not then I know something went wrong.  So I
use a case statement to match the pattern.  It's built into the
shell and very fast.

    used=$(df / | awk '$NF=="/"{print$5}')
    : "debug: case $used in"
    case $used in
        [0-9]*%) : "debug: pattern matches [0-9]*% okay" ;;
        *) echo "Error: df /: failed: Use%=$used" 1>&2; exit 1 ;;
    esac

Matches are made top to bottom with the first pattern match winning.
Therefore I test for the good pattern first and anything else will be
an error.

Most of the time though the output will be something more arbitrary.
In order to check that it worked there then the exit code plus the
expected output is best.  Because df might fail.  What if the system
is overloaded and can't get a process slot?  What if the mount point
has a disk failure?

    swap_total_configured=$(awk '/^SwapTotal:/{print$2}' /proc/meminfo)
    if [ -z "$swap_total_configured" ]; then
        echo "Error: Missing: /proc/meminfo: SwapTotal entry" 1>&2
        exit 1
    fi

That handles checking the exit code of the process being invoked too.
But if it is important then check the exit code of the command
substitution too.

    if ! dd if=/dev/zero of=/swapfile1 bs=1M count=$ddcount; then
        echo "Error creating swap space" 1>&2
        exit 1
    fi

Here if the dd fails then the if condition will report it.

I hate to mention it but other than df the GNU stat command will also
return file system information.  I hate to mention it because stat is
not portable across most systems.  The BSD stat command is different.
And the classic Unix system stat command is different.  But if one is
working with GNU stat then it can also be used to get file system
information more directly.

    ‘-f’
    ‘--file-system’
         Report information about the file systems where the given files are
         located instead of information about the files themselves.  This
         option implies the ‘-L’ option.

       When listing file system information (‘--file-system’ (‘-f’)), you
    must use a different set of FORMAT directives:

       %a - Free blocks available to non-super-user
       %b - Total data blocks in file system
       %c - Total file nodes in file system
       %d - Free file nodes in file system
       %f - Free blocks in file system
       %i - File System ID in hex
       %l - Maximum length of file names
       %n - File name
       %s - Block size (for faster transfers)
       %S - Fundamental block size (for block counts)
       %t - Type in hex
       %T - Type in human readable form

The tricky thing here is that everything is reported in number of
blocks.  How big is a block?  Have to ask it.  It's 4096 on my system.

    blocksize=$(stat -f --format="%S" /)

To get the number of available blocks.

    stat -f --format="%a" /

To get the number of total blocks.

    stat -f --format="%b" /

And then to compute the percentage available can use shell integer math.
In which case the block size is not needed.

    echo Available = $(( 100 * $(stat -f --format="%a" /) / $(stat -f --format="%b" /) )) percent
    Available = 32 percent

    echo Used = $(( 100 * $(( $(stat -f --format="%b" /) - $(stat -f --format="%f" /) )) / $(stat -f --format="%b" /) )) percent
    Used = 63 percent

It's fine but I would normally prefer df and awk to get this information.

Bob


More information about the NCLUG mailing list