#!/usr/bin/perl # Filename: colmath # Author: David Ljung Madison # See License: http://MarginalHacks.com/License/ # Description: Column math. See usage. use strict; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; my ($BASENAME,$PROGNAME) = ($0 =~ m|(.*)/(.+)|) ? ($1?$1:'/',$2) : ('.',$0); ################################################## # Usage ################################################## sub fatal { foreach my $msg (@_) { print STDERR "[$PROGNAME] ERROR: $msg\n"; } exit(-1); } sub usage { foreach my $msg (@_) { print STDERR "ERROR: $msg\n"; } print STDERR "\n"; print STDERR "Usage:\t$PROGNAME [-d] \n"; print STDERR "\tCut columns from files and do 'math' on the results\n"; print STDERR "\t+ adds a file, - subtracts, order is important!\n"; print STDERR "\n"; print STDERR "\t-d \tDelimiter\n"; print STDERR "\t-f \tField to cut\n"; print STDERR "\t-i\tIgnore case\n"; print STDERR "\t-ignore \tIgnore these lines (regexp)\n"; print STDERR "\n"; print STDERR "\t-D\tSet debug mode\n"; print STDERR "\n"; exit -1; } sub parse_args { my %opt = ( 'delim' => "\t", 'field' => 1, ); while (my $arg=shift(@ARGV)) { if ($arg =~ /^-h$/) { usage(); } if ($arg =~ /^-i$/) { $opt{ic} = 1; next; } if ($arg =~ /^-d(=(.+))?$/) { $opt{delim} = $2 ? $2 : shift(@ARGV); next; } if ($arg =~ /^-f(=(.+))?$/) { $opt{field} = $2 ? $2 : shift(@ARGV); next; } if ($arg =~ /^-ignore(=(.+))?$/) { $opt{ignore} = $2 ? $2 : shift(@ARGV); next; } if ($arg =~ /^-D$/) { $MAIN::DEBUG=1; next; } if (-f $arg) { push(@{$opt{files}}, $arg); next; } if ($arg =~ /^[\+\-](.+)/ && -f $1) { push(@{$opt{files}}, $arg); next; } usage("Unknown option/file: [$arg]"); } usage("No files defined") unless $opt{files} && @{$opt{files}}; \%opt; } sub debug { return unless $MAIN::DEBUG; foreach my $msg (@_) { print STDERR "[$PROGNAME] $msg\n"; } } ################################################## # Code ################################################## sub get_file { my ($opt,$file) = @_; # Add or subtract? my $add = 1; unless (-f $file) { $add = 0 if !($file =~ s/^\+//) && $file =~ s/^\-//; } open(FILE,$file) || usage("Couldn't open file: $file"); my @fields; while() { next if $opt->{ignore} && /$opt->{ignore}/; chomp; my @cols = split($opt->{delim}); my $col = $cols[$opt->{field}]; push(@fields, $col) if $#cols+1>=$opt->{field}; } close(FILE); ($add, @fields); } ################################################## # Main code ################################################## sub main { my $opt = parse_args(); my %final; foreach my $file ( @{$opt->{files}} ) { my ($add,@fields) = get_file($opt,$file); foreach my $field ( @fields ) { my $key = $opt->{ic} ? lc($field) : $field; $final{$key}=$field if $add; delete $final{$key} unless $add; } } foreach my $key ( sort keys %final ) { print "$final{$key}\n"; } } main();