#!/usr/bin/perl -w use Getopt::Long; use Math::Calc::Units qw(convert readable calc); sub usage { my ($msg, $bad) = @_; my $out = $bad ? *STDERR : *STDOUT; if ($msg) { print $out "$0: $msg\n"; } print $out <<"END"; usage: Calculate the given expression, and guess human-readable units for the result: $0 [-v] [-a] Convert the given expression to the requested units: $0 -c $0 --convert Examples: How long does it take to download 10MB over a 384 kilobit/sec connection? $0 "10MB / 384Kbps" What is the expected I/O rate for 8KB reads on a disk that reads at 20MB/sec and has an average seek time of 15ms? $0 "8KB / (8KB/(20MB/sec) + 15ms)" Or if you prefer to calculate that by figuring out the number of seconds per byte and inverting: $0 "((1sec/20MB) + 15ms/8KB) ** -1" How many gigabytes can you transfer in a week at 2MB/sec? $0 -c "2MB/sec" "GB/week" How many angels fit on the heads of 17 pins (with some assumptions)? (This demonstrates that unknown units are allowed, with plurals.) $0 "42 angels/pinhead * 17 pinheads" END exit($bad ? 1 : 0); } my $verbose = 0; my $abbreviate = 0; my $action = 'readable'; GetOptions("verbose|v!" => \$verbose, "abbreviate|abbrev|a" => \$abbreviate, "convert|c!" => sub { $action = 'convert' }, "help|h!" => sub { usage("", 0) }, ) or usage("invalid arguments", 1); if ($action eq 'convert') { usage("not enough args", 1) if (@ARGV < 2); usage("too many args", 1) if (@ARGV > 2); print convert($ARGV[0], $ARGV[1]), "\n"; } elsif ($action eq 'readable') { usage("", 0) if @ARGV == 0; usage("too many ARGV", 1) if (@ARGV > 1); print "$_\n" foreach readable($ARGV[0], verbose => $verbose, abbreviate => $abbreviate); } 1;