Cleaning Up Long Conditionals With Grep

Every so often I am faced with testing a few conditionals before dropping into another control structure. If you have to test out a few conditionals, then its likely a dispatch table won’t be useful. If you have a lot of conditionals to test, you’ll likely not want to deal with an ugly expression like the following:

if ( (defined $SITE{$partner}{'foo'} && ($SITE{$partner}{'foo'} > 0) ) and
        ( (defined $assoc{'foo'} && ($assoc{'foo'} > 0)) or
          (defined $assoc{'bar'} && ($assoc{'bar'} > 0)))
   ) {
print "We're here!\n";
}

One of the ways to deal with it to to use grep. Since grep returns the number of elements in the array that evaluate to true (when called in a scalar context), I can do the following to make it work:

my @foo = [ $SITE{$partner}{'foo'}, $assoc{'foo'}, $assoc{'bar'} ];
if ( (grep {defined($_) and $_ > 0} @foo) > 2) { print "We're here!\n"; }

The reason this works is that when called in the scalar context, grep only returns the number of elements that evaluate to true. Since there are 3 elements in the array, the return value is greater than 2, then the entire expression evaluates to true. This is not only a lot easier to read and a lot cleaner to write, but it makes for easy additions to the conditional testing if necessary. Although changing the context in which functions are called is common, it is easily forgotten. Grep called in scalar context can be easily manipulated (as above) to add readability to your program.

Posted in Perl. Tags: , . 1 Comment »

Mac Perl Problems After Feb Update

When I did my most recent upgrade (the latest Mac software updates), it broke my Perl install. In order to figure out if your Perl is broken like mine was, you will get a result like this:

beacon:mail elubow$ perl -MIO
IO object version 1.22 does not match bootstrap parameter 1.23 at /System/Library/Perl/5.8.8/darwin-thread-multi-2level/XSLoader.pm line 94.
Compilation failed in require.
BEGIN failed--compilation aborted.

I had a little trouble finding out how to fix this. So I am posting this here in case it helps someone else out. It was a simple fix (since CPAN doesn’t work) that you have to do by hand. Go to the CPAN site and download dist IO here. Download and untar it and run the following commands:

beacon:IO-1.2301 elubow$ sudo perl Makefile.PL
Writing Makefile for IO
beacon:IO-1.2301 elubow$ sudo make install
cc -c   -arch i386 -arch ppc -g -pipe -fno-common -DPERL_DARWIN -no-cpp-precomp -fno-strict-aliasing -Wdeclaration-after-statement -I/usr/local/include -O3   -DVERSION=\"1.23\" -DXS_VERSION=\"1.23\"  "-I/System/Library/Perl/5.8.8/darwin-thread-multi-2level/CORE"   IO.c
...
<strong>Removed for brevity</strong>
...
Files found in blib/arch: installing files in blib/lib into architecture dependent library tree
Installing /System/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/IO/IO.bundle
Writing /System/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/IO/.packlist
Appending installation info to /System/Library/Perl/5.8.8/darwin-thread-multi-2level/perllocal.pod

This should fix your Perl install. It also ended up that I had to run CPAN and reinstall Scalar::Util and Storable.

Posted in Mac, Perl. Tags: , , . 1 Comment »

Creating a Process Table hash in Perl

I came across a situation where I needed to access the process table in Perl. The problem that i found was that the best accessor Proc::ProcessTable only retrieved an array. Since it seems fairly senseless to keep looping over an array to find the exact process id that I want, you may want to turn it into a hash.

use strict;
use warnings;
use Proc::ProcessTable;

 # Create a new process table object
 my ($pt) = new Proc::ProcessTable;

 # Initialize your process table hash
 my (%pt_hash);

 # Get the fields that your architecture supports
 my (@fields) = $pt->fields;

 # Outer loop for each process id
 foreach my $proc ( @{$pt->table} ) {
    # Inner loop for each field within the process id
    for my $field (@fields) {
       # Add the field to the hash
       $pt_hash{$proc->pid}{$field} = $proc->$field();
    }
 }

It’s just as simple as that. If you want to be sure that its in there. At the end of the file add these two lines for proof:

use Data::Dumper;
print Dumper \%pt_hash;

The hash is organized with the keys being the process ids. There is another hash underneath it with all the fields as hash keys.

Posted in Perl. Tags: , . 1 Comment »

File::ReadBackwards

Description: File::ReadBackwards works similar to the linux shell command tac. It reads the file line by line strarting from the end of the file.

CPAN: File::ReadBackwards

Example 1:
Being a System’s Administrator, I am usually doing some analysis on a large logfile. Therefore, I may not need all the information contained in the log. This may be especially true if the logs only get rotated once a day or once a week and I don’t need all the information in the log file. Using File::ReadBackwards in combination with a date and time calculation module, I can take only the amount of time I want to use from the logs and then stop processing there. Since we aren’t covering the date calculations here, I will push those out to another subroutine that we will assume works.

# Always use these
use strict;
use warnings;

# Use the module itself
use File::ReadBackwards;

# Define the log file to be read
my $log = "/var/log/log_file";

# Open the logfile by tie'ing it to the module
tie *LOG, "File::ReadBackwards", "$log"
   or die ("$log tie error: $!");

# Iterate over the logfile
while (my $line = ) {

  # Split the log line
  my @entry = split(/\s+/, $line);

  # Take the timestamp and check if we
  #   have hit our threshold yet
  # Break loop if we have
  last if (time_reached($entry[0]) == 1);
}

# Cleanup
untie (*LOG);