ministry has asked for the wisdom of the Perl Monks concerning the following question:

What is going to be the easiest way to find out how much disk space capacity has been utilized on a particular slice? For example, when I attempted this in a shell script, my syntax was as follows (to find the root partitions capacity):

SLICE1=`/bin/df -k|/bin/egrep "/^"|/bin/awk '{print $5}'`

Here I just used the output of a /bin/df -k and printed out the one value I was looking for. Should I simply pipe a df -k from the shell into my perl script, and trim up the output a bit, or is there a better way?

Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement.

Replies are listed 'Best First'.
Re: disk space utilization
by saintmike (Vicar) on Apr 08, 2005 at 20:06 UTC
Re: disk space utilization
by xorl (Deacon) on Apr 08, 2005 at 19:53 UTC
Re: disk space utilization
by ambrus (Abbot) on Apr 08, 2005 at 20:08 UTC

    I wonder how "/^" could match anything in the command you've given. Anyway, df /foo/bar lists the data only for the filesystem that contains the file /foo/bar (which can be the root file system, or a fs mounted on /foo or on /foo/bar).

    The pure perl solution is to use ustat or statfs:

    sub __NR_statfs () { 99 }; $file = "/"; $s = pack "x256"; -1 == syscal +l(__NR_statfs, "".$file, $s) and die "error statfs: $!"; (undef, $bsi +ze, undef, $bfree, $bavail) = unpack "l!5", $s; print $bavail*$bsize/ +1024, " kilobytes available\n";

    Update: statfs is linux-specific (Update: except not really, but the structure might be different, I don't know). Ustat might be usable on other systems too.

    Update 2006 sep: note that system call numbers are different on every architecture (OS and CPU type). You have to look up the syscall number of your architecture.

Re: disk space utilization
by gam3 (Curate) on Apr 08, 2005 at 20:18 UTC
    This may be one of the few cases where awk is the correct solution.
    df -P | awk '/^\//{printf("%5s %s\n", $5, $6);}'
    df -P | perl -ne 'printf("%5s %s\n", (split(/\s+/, $_))[4, 5])'
    If you want to do a lot more formating; then I would write a complete perl program.

    use Filesys::Statvfs; open MOUNTED, "</proc/mounts" || die "Could not open /proc/mounted\n"; while (my $mountpoint = <MOUNTED>) { my ($bsize, $blocks, $bfree, $bavail, $files, $ffree, $namelen); my $path = (split(/\s+/, $mountpoint))[1]; if (1) { ($ftype, $bsize, $blocks, $bfree, $files, $ffree, $bavail) = statvfs("/tmp"); } else { # This is not very portable my $buf = "\0"x64; syscall(99, $path, $buf) == 0 or die "Bad mountpoint $path\n"; ($bsize, $blocks, $bfree, $bavail, $files, $ffree, $namelen) = unpack "x4 L6 x8 L", $buf; } next unless $blocks; print <<EOT; path: $path Optimal transfer block size: $bsize Blocks in file system: $blocks Blocks free: $bfree (${\(int $bfree/$blocks*100)} +%) User blocks available: $bavail (${\(int $bavail/$blocks*100 +)}%) Inodes: $files Free inodes: $ffree (${\(int $ffree/$files*100)}% +) EOT }
    -- gam3
    A picture is worth a thousand words, but takes 200K.
Re: disk space utilization
by sh1tn (Priest) on Apr 08, 2005 at 19:41 UTC
    df -k | perl -ne '/(\S+\s+){4}(\S+)/&&print$2.$/' -

      Perl's "-a" command-line option allows you to pretend that you're using something that resembles "awk" (that's why it's "-a") -- differences between "perl -a" and "awk" are that perl uses @F where awk uses $1,$2,..., and the first token on the line is $F[0] instead of $1:
      df -k | perl -lane 'print $F[3]'
      (the "-l" option helps make line-feed handling more like awk as well). I presume this still doesn't do exactly what the OP intended, since it prints a line of output for every line of input from "df -k"; but the OP's use of "grep '/^' " seems odd -- not sure what's intended by that.

      To limit the output to a particular line, one can cite the target path as an arg to "df", and/or use a condition in the perl script:

      df -k / | perl -lane 'print $F[3] if /\d/' # skips column headings # or just: df -k | perl -lane 'print $F[3] if m{/$}' # only prints value for "/ +"
        Thanks for the info graff, the use of an expression grep "/^" in the middle of my arguement will only report back the line of output in the df -k that has a slash that is immediately followed by an end of line tag (anchor)- thereby only returning the root partition, as opposed to only doing a basic grep for a slash, which will return every slice starting with a slash (working in ksh).
        Is there any way I can incorporate your 'one-liner' into my script? As this is only one function out of several that needs to be performed.

        Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement.