On Mon, 10 Aug 2009 00:24:06 +0200
houghi <houghi DeleteThis @houghi.org.invalid> wrote:
>-------------------------------------------------------------------
>All in GB 4582G 1226G 3123G
>All in TB 4.47T 1.19T 3.04T 26% @penne x86_64
>-------------------------------------------------------------------
>
>And that was the information I wanted.
>
Recently, I had to learn about Perl's 'format' statement, so I figured
I would use your df problem as a test case. I include it here for you
to do with as you please.

Save the text between the lines of equal
signs to a file in a convenient location. If you want to be able to
execute it directly, make sure to make it executable. If you don't want
to do that, just run it with perl:
perl yourscriptname
It is definitely not optimized code -- but I try to write
understandable code instead of obfuscated code so more
programmers can follow it.
Also, I included peta, exa, zetta and yotta conversions for when we
finally get decent sized disks!
Enjoy!
=============================================================
#!/usr/bin/perl
use strict;
use warnings;
# Get the 'df' data:
my @raw = `df --portability --print-type --human-readable`;
# Fix column title with space in it:
$raw[0] =~ s/Mounted\s+on/Mounted_on/gmx;
# Pull off the first line of the data (column names) and put them in array:
my $firstline = shift @raw;
my @title = split '\s+', $firstline;
# Define our multipliers / dividers:
my $kilo = 1024;
my $mega = 1024 * 1024;
my $giga = $mega * 1024;
my $tera = $giga * 1024;
my $peta = $tera * 1024;
my $exa = $peta * 1024; # just for the helluvit!
my $zetta = $exa * 1024; # just for the helluvit!
my $yotta = $zetta * 1024; # just for the helluvit!
# Get lengths for adjustable display table:
my $maxlen1 = 0; # Filesystem max length
my $maxlen2 = 0; # Mounted On max length
my $arrhash = ();
my $totalsize = 0;
my $totalused = 0;
my $totalavail = 0;
# Build a hash from raw array, to reduce use of array subscripting:
foreach my $line (@raw) {
my @tmp = split '\s+', $line;
push @{$arrhash},
{
'filesystem' => $tmp[0],
'type' => $tmp[1],
'size' => $tmp[2],
'used' => $tmp[3],
'avail' => $tmp[4],
'percent' => $tmp[5],
'mounted_on' => $tmp[6],
};
# Total everything up in bytes:
$totalsize += &convert_to_bytes( $tmp[2] ) if $tmp[2];
$totalused += &convert_to_bytes( $tmp[3] ) if $tmp[3];
$totalavail += &convert_to_bytes( $tmp[4] ) if $tmp[4];
# Adjust the max lengths:
$maxlen1 = $maxlen1 < ( length $tmp[0] ) ? length $tmp[0] : $maxlen1;
$maxlen2 = $maxlen2 < ( length $tmp[6] ) ? length $tmp[6] : $maxlen2;
}
print_result( \@title, $arrhash );
exit;
#
# Now for the support routines
#
sub convert_to_bytes {
my ($valstr) = @_;
my $mult = 1;
if ( $valstr =~ m/K/ ) {
$mult = $kilo;
}
elsif ( $valstr =~ m/M/ ) {
$mult = $mega;
}
elsif ( $valstr =~ m/G/ ) {
$mult = $giga;
}
elsif ( $valstr =~ m/T/ ) {
$mult = $tera;
}
elsif ( $valstr =~ m/P/ ) {
$mult = $peta;
}
elsif ( $valstr =~ m/E/ ) {
$mult = $exa;
}
elsif ( $valstr =~ m/Z/ ) {
$mult = $zetta;
}
elsif ( $valstr =~ m/Y/ ) {
$mult = $yotta;
}
# Strip out the non-numerics (K,M,G, etc.)
$valstr =~ s|[^0-9.]||igmx;
# I got some fractional bytes (?) before adding the 'int':
return int( $valstr * $mult );
}
sub print_result {
my ( $title, $arrhash ) = @_;
my $filesystem;
my $size;
my $used;
my $avail;
my $percent;
my $type;
my $mounted_on;
# setup the default format string:
my $format =
"format STDOUT = \n" . '@'
. '<' x ($maxlen1)
. '@>>>>>>> '
. '@>>>>>>> '
. '@>>>>>>> '
. '@>>>>>>> '
. '@>>>>>>> ' . '@'
. '<' x ($maxlen2) . "\n"
. '$filesystem,'
. '$size,'
. '$used,'
. '$avail,'
. '$percent,'
. '$type,'
. '$mounted_on' . "\n.";
# Need to 'eval' it because format strings are interpreted at compile time;
eval $format;
die $@ if $@; # In case there are any errors during eval
# Put our column titles into format variables:
$filesystem = $title[0];
$size = $title[2];
$used = $title[3];
$avail = $title[4];
$percent = $title[5];
$type = $title[1];
$mounted_on = $title[6];
# And then print them:
write;
# Cycle through the actual values, placing them in the format variables:
foreach my $hash ( @{$arrhash} ) {
$filesystem = $hash->{'filesystem'};
$size = $hash->{'size'};
$used = $hash->{'used'};
$avail = $hash->{'avail'};
$percent = $hash->{'percent'};
$type = $hash->{'type'};
$mounted_on = $hash->{'mounted_on'};
write;
}
print "\n"; # Blank line before totals.
no warnings;
my $scalename;
my $amt;
my $format2 =
"format STDOUT = \n"
. '@>>>>>>>>>>>>> '
. '@#############.#### ' . "\n"
. '$scalename,' . '$amt' . "\n.";
eval $format2;
die $@ if $@;
use warnings;
# Should re-design this to use loops (but this was just so easy to do!):
print " Total Size: \n"; # $totalsize ( B)
$scalename = 'KB:';
$amt = round_bytes( $totalsize / $kilo );
write unless $amt < 0.0001;
$scalename = 'MB:';
$amt = round_bytes( $totalsize / $mega );
write unless $amt < 0.0001;
$scalename = 'GB:';
$amt = round_bytes( $totalsize / $giga );
write unless $amt < 0.0001;
$scalename = 'TB:';
$amt = round_bytes( $totalsize / $tera );
write unless $amt < 0.0001;
$scalename = 'PB:';
$amt = round_bytes( $totalsize / $peta );
write unless $amt < 0.0001;
$scalename = 'EB:';
$amt = round_bytes( $totalsize / $exa );
write unless $amt < 0.0001;
$scalename = 'ZB:';
$amt = round_bytes( $totalsize / $zetta );
write unless $amt < 0.0001;
$scalename = 'YB:';
$amt = round_bytes( $totalsize / $yotta );
write unless $amt < 0.0001;
print " Total Used: \n"; # $totalused ( B)
$scalename = 'KB:';
$amt = round_bytes( $totalused / $kilo );
write unless $amt < 0.0001;
$scalename = 'MB:';
$amt = round_bytes( $totalused / $mega );
write unless $amt < 0.0001;
$scalename = 'GB:';
$amt = round_bytes( $totalused / $giga );
write unless $amt < 0.0001;
$scalename = 'TB:';
$amt = round_bytes( $totalused / $tera );
write unless $amt < 0.0001;
$scalename = 'PB:';
$amt = round_bytes( $totalused / $peta );
write unless $amt < 0.0001;
$scalename = 'EB:';
$amt = round_bytes( $totalused / $exa );
write unless $amt < 0.0001;
$scalename = 'ZB:';
$amt = round_bytes( $totalused / $zetta );
write unless $amt < 0.0001;
$scalename = 'YB:';
$amt = round_bytes( $totalused / $yotta );
write unless $amt < 0.0001;
print " Total Avail: \n"; # $totalavail ( B)
$scalename = 'KB:';
$amt = round_bytes( $totalavail / $kilo );
write unless $amt < 0.0001;
$scalename = 'MB:';
$amt = round_bytes( $totalavail / $mega );
write unless $amt < 0.0001;
$scalename = 'GB:';
$amt = round_bytes( $totalavail / $giga );
write unless $amt < 0.0001;
$scalename = 'TB:';
$amt = round_bytes( $totalavail / $tera );
write unless $amt < 0.0001;
$scalename = 'PB:';
$amt = round_bytes( $totalavail / $peta );
write unless $amt < 0.0001;
$scalename = 'EB:';
$amt = round_bytes( $totalavail / $exa );
write unless $amt < 0.0001;
$scalename = 'ZB:';
$amt = round_bytes( $totalavail / $zetta );
write unless $amt < 0.0001;
$scalename = 'YB:';
$amt = round_bytes( $totalavail / $yotta );
write unless $amt < 0.0001;
}
use POSIX;
sub round_bytes {
my ( $raw, $places ) = @_;
return 0 unless $raw; # Must have a value on which to work!
$places = 4 unless $places; # Provide default, just in case
my $scale = 10**$places;
return POSIX::floor( ( $raw * $scale ) + 0.5 ) / $scale;
}
=============================================================
--
Kevin Nathan (Arizona, USA)
Linux Potpourri and a.o.l.s. FAQ -- (temporarily offline)
Open standards. Open source. Open minds.
The command line is the front line.
Linux 2.6.25.20-0.4-pae
1:07am up 25 days 2:29, 35 users, load average: 0.32, 0.28, 0.27