#!/usr/bin/perl # add - to add those numeric columns on stdin, report totals for cols and # grand total, plus number of items/col that are addable (numeric) # (c) 1995-2004 ken chase # this code is useable/distributable under the GPL liscence #changelog # 1995 - first version # 1997 - added -p option to produce what -p and -r does now # 2000 feb 25 - added -r to seperate lines and totals, and -h # 2000 mar 2 - added -t to specify column seperator # 2001 nov 26 - allowed addition of -ve numbers (not delete lead - sign) # - fixed subtracting columns (-# was conflicting w/getopt parse) # 2002 nov 26 - made default compression of field seps, -n turns off # - added -P pure numbers switch # - design almost implicitly made negative columns (-1) be count # from right side (ie Nth col is -1), fixed up code to support # 2004 sep 4 - ignore leading blank chars -i # - -v verbose option # 2008 may 29 - fixed so leading .05 becomes 0.05 not '5' $version = "v0.84 29 may 08 math @ sizone.org"; use Getopt::Long; # auto parse options Getopt::Long::Configure ("bundling"); # allow -(opt)(opt)(opt) # parse options with Getopt::Long module $Getopt::Long::ignorecase = 0; # we dont want to ignore option case $result = GetOptions ("p","r","h", "d", "t=s", "n", "P", "i", "v"); if ($opt_h) { print STDERR "$0 $version usage: $0 (space seperated column list, 0-n) adds all numbers in columns (0-n) on command line from STDIN. use (column#)- to indicate subtract column instead. (- must be last char) use -(column#) to count columns from right side. (5 cols w/ $0 5 -1 will produce two totals, one for col 5 and one for col -1, despite same col) -p to print each line of input with the output -r to give (interleaved with -p) running total -d to give debug output column by column (nasty mess, implies -r) -t '(char)' to use char as seperator for columns (\\t for tab) (default \\s) -n makes split char non-globbing (ie 3 chars = 2 empty fields between) -i ignore leading blank seperator chars (ie \" 5\" is field 1 = 5 when -t \" \") -v slightly more verbose output per column switches (can be used -P (for eg) to apply to all fields, or to modify columns such as '1P-' for 2nd column subtraction of only pure numbers (note: negative fields have - sign AFTER modifiers) -P pure numbers - add a field if it consists only of chars (^-|[0-9]) (note, total number of additions doesnt include skipped impure numbers) "; exit 1; } if ($opt_v) { print "columns to add: ", join(":", @ARGV), "\n"; } $gtotal = 0; $gtotalnum = 0; $splitchars = '\s'; $splitchars = $opt_t if $opt_t; $opt_r = 1 if $opt_d; # -r implied by -d print "Splitting on:`", $opt_t, "`\n" if $opt_t; while () { chop; $line = $_; if ($opt_i) { $line =~ s/^$splitchars*//; } if ($opt_n) { # no glob of split chars? split(/$splitchars/,$line); } else { split(/$splitchars+/,$line); } if ($opt_p) { print $_, "\n"; } for $col (@ARGV) { $col1 = $col; $col1 =~ s/[^0-9-]//g; # strip non numeric or - $col1 =~ s/\-$//g; # strip trailing - $mult = 1; ($col =~ /\-$/) && ($mult = -1); # substract column instead $numbers{$col} ||= 0; # start row count for col at 0 print " Col $col line $numbers{$col}:'", $_[$col1], "'\n" if $opt_d; $num = $_[$col1]; # get the number $num =~ y/\n//d; $num1 = $num; # strip \n and make copy $num =~ s/^\./0./; # leading .## is 0.## $num =~ s/^[^0-9-]*//; # erase leading non numeric $num = $num * $mult; if ( ( ($opt_P || $col =~ /P/) && ($num1 eq abs($num)) ) || !($opt_P || $col =~ /P/) ) { $oldtot = $total{$col}; # keep around for debug $oldtot ||= 0; $total{$col} += $num; $numbers{$col}++; if ($opt_d) { print " adding value: '$num' "; } if ($opt_r) { print $numbers{$col}, ": $oldtot + '$num' = ", $total{$col}, " \n"; } } else { if ($opt_d) { print " not adding non-pure value: '$num1' "; } } ($opt_d) && (print "\n"); } if ($opt_r) { print "\n"; } } print "\n"; for $col (@ARGV) { if ($opt_v) { print "(", $col, ":", $numbers{$col}, ") ", $total{$col}, "\t"; } $gtotal += $total{$col}; $gtotalnum += $numbers{$col}; } if ($opt_v) { print "\ngrand total for $gtotalnum lines: "; } print "$gtotal\n"; # no buffer STDERR output so we can watch progress... select STDERR; $| = 1; # set no buffering for selected filehandle select STDOUT;