Posts Tagged ‘ Perl ’

ec2-consistent-snapshot With Mongo

Thursday, April 21st, 2011

I setup MongoDB on my Amazon EC2 instance knowing full well that it would have to be backed up at some point. I also knew that by using XFS, I could take advantage of filesystem freezing in a similar fashion to LVM snapshots. I had remembered reading about backups on XFS with MySQL being done with ec2-consistent-snapshot. As with any piece of open source software, it just took a little tweaking to make it do what I wanted it to do.
(more…)

Hash Autovivification in Ruby

Wednesday, October 6th, 2010

One of the features that I miss most from my Perl days (and to be honest, there isn’t a whole lot I miss from my Perl days) is autovivification. For more information on what it is, read the wikipedia page on it here.
(more…)

Using Unique Keys and Key Groups with Background Jobs in Gearman::Client

Wednesday, June 16th, 2010

While diving into Gearman using Gearman::Client with MySQL and libdrizzle (I know, a mouthful), I ran into what I thought was a bug. I was only able to add 1 background job of any type at a particular time. The launchpad “bug note,” which is available in its entirety here, is rightly labeled won’t fix.
(more…)

Monitoring Services with Nagios::Plugin

Wednesday, April 7th, 2010

There are a lot of people who say, “if it isn’t monitored, then it isn’t a service.” The problem is that I don’t think enough people outside of the systems world believe that or even understand why its said. I think the primary offenders here are developers. It isn’t because they don’t know better, but typically developers just want to get the application up and running and then move on to developing the next thing. I also think there is some fault on the side of the administrators and the managers not insisting that part of the completed version of a project includes monitoring. But I don’t want to harp on this as much as I would like to show just how easy it is to compensate here by taking advantage of Nagios::Plugin.
(more…)

File Read Write Create with IO::File

Friday, November 20th, 2009

Ran into an annoying gotchya with Perl’s IO::File. Apparently opening the file in append mode with read access if the file already exists puts the file position pointer at the end of the file. If it doesn’t exist, it creates the file. Note the +>>, that opens the file r/w/append. You can also use the more common (and more easily recognizable) form of a+.

1
2
3
4
5
    my $FH = new IO::File "$file", "+>>";
    while (my $line = $FH->getline()) {
      print "Line: $line\n";
    }
    undef $FH;

I noticed that when I tried to read the file (if it already existed), then nothing would be read. I neglected to realize that you must seek to position 0 in the file if you want to read it. Therefore the following code will work:

1
2
3
4
5
6
    my $FH = new IO::File "$file", "+>>";
    $FH->seek(0,0);
    while (my $line = $FH->getline()) {
      print "Line: $line\n";
    }
    undef $FH;

Although it might seem obvious that you need to be at the beginning of the file to read it forward (and it is), I didn’t realize the file pointer opened a file in append mode to the last position in the file (in hind sight, it does appear to be a bit more obvious).

Testing For A Number

Thursday, April 16th, 2009

Although you generally don’t have to worry about types in Perl, it is occasionally necessary to ensure that you are working with numbers. Your test cases should notify you that something is amiss when you didn’t get a number (when you were expecting one). Thankfully Scalar::Util provides a method to deal with this.

1
2
3
4
5
6
7
use Scalar::Util qw( looks_like_number );

my @possibleNumbers = qw(1 5.25 word 4);

foreach my $nums (@possibleNumbers) {
       print "$nums is", looks_like_number($nums) ? '' : ' not', " a number\n";
}

This will print:

1
2
3
4
1 is a number
5.25 is a number
word is not a number
4 is a number

This neat little method takes advantage of Perl C API’s looks_like_number() function. Since this is virtually native, it will be pretty fast.

Cleaning Up Long Conditionals With Grep

Tuesday, April 7th, 2009

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:

1
2
3
4
5
6
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:

1
2
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.

Mac Perl Problems After Feb Update

Sunday, March 8th, 2009

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:

1
2
3
4
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:

1
2
3
4
5
6
7
8
9
10
11
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.

Creating a Process Table hash in Perl

Friday, December 28th, 2007

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.

File::Bidirectional

Friday, March 9th, 2007

Description: The author of this module notes that it is best used, especially by him, when reading or manipulating log files. I have a tendency to use it for the exact same thing, especially when looking for context around captured lines.

CPAN: File::Bidirectional

Note:
Although I would like to note that using the tie’d interface as I have done takes approximately 2 1/2 times as long as a regular file read according to benchmarks, it is still a very handy tool and allows one not to reinvent the wheel.

Example 1:
Here we are going to go through a log file and when we hit the time stamp we want, we are going to change directions and go back through. There is no real reason to change direction here, I am merely demonstrating how it would be accomplished.

# Always use these
use strict;
use warnings;

# Use the module itself
use File::Bidirectional;

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

# Open the logfile by tie'ing it to the module
#  This is exactly the same as File::ReadBackwards
tie *LOG, "File::Bidirectional", "$log", {mode => 'backward'}
   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
  # Get the line # then change direction
  if (time_reached($entry[0]) == 1) {
    $line_num = (tied *LOG)->line_num();
    (tied *LOG)->switch();
  }
}

# Cleanup
untie (*LOG);

Mail::IMAPClient

Tuesday, January 23rd, 2007

Description: Recently, I have had the pleasure of getting knee deep into various aspects of Email. One of the things that I consistantly found myself wanting to do was to parse through it. I know the best way to do this is to connect to the IMAP server and download the messages. The best way I have come accross on how to accomplish this task is using Mail::IMAPClient.

CPAN: Mail::IMAPClient

Example 1:
Creating a connection to an IMAP server isn’t complicated. And once you are connected there are many things that you can do to manipulate messages. In this first example, I am merely going to show you how to connect to the mail server and download ALL the messages in specific folders:

# Always be safe
use strict;
use warnings;

# Use the module
use Mail::IMAPClient;

 $imap = Mail::IMAPClient->new( Server  => 'mail.server.com:143',
                                User    => 'me',
                              Password  => 'mypass')
        # module uses eval, so we use $@ instead of $!
        or die "IMAP Failure: $@";

 foreach my $box qw( HAM SPAM ) {
   # Which file are the messages going into
   my $file = "mail/$box";

   # Select the mailbox to get messages from
   $imap->select($box)
        or die "IMAP Select Error: $!";

   # Store each message as an array element
   my @msgs = $imap->search('ALL')
        or die "Couldn't get all messages\n";

   # Loop over the messages and store in file
   foreach my $msg (@msgs) {
     # Pipe msgs through 'formail' so they are stored properly
     open my $pipe, "| formail >> $file"
       or die("Formail Open Pipe Error: $!");

     # Send msg through file pipe
     $imap->message_to_file($pipe, $msg);

     # Close the messgae pipe
     close $pipe
       or die("Formail Close Pipe Error: $!");
   }

   # Close the folder
   $imap->close($box);
 }

 # We're all done with IMAP here
 $imap->logout();

Example 2:
In this next example, we are going to take advantage of some other methods that are provided by this useful little module. We will begin by using the same base as is in Example 1, but we will add some nuances in the middle for functionality.

Note: Messages don’t get immediately deleted with IMAP, only marked for deletion. They aren’t actually deleted until the box is expunged. In this case, it gets done after the looping over each mailbox is complete. This is to say that if the program gets interrupted in the middle that the messages won’t be deleted until the mailbox is officially issued an expunge command.

# Always be safe
use strict;
use warnings;

# Use the module
use Mail::IMAPClient;

 $imap = Mail::IMAPClient->new( Server  => 'mail.server.com:143',
                                User    => 'me',
                              Password  => 'mypass')
        # module uses eval, so we use $@ instead of $!
        or die "IMAP Failure: $@";

 foreach my $box qw( HAM SPAM ) {
   # How many msgs are we going to process
   print "There are ". $imap->message_count($box).
          " messages in the $box folder.\n";

   # Which file are the messages going into
   my $file = "mail/$box";

   # Select the mailbox to get messages from
   $imap->select($box)
        or die "IMAP Select Error: $!";

   # Store each message as an array element
   my @msgs = $imap->search('ALL')
        or die "Couldn't get all messages\n";

   # Loop over the messages and store in file
   foreach my $msg (@msgs) {
     # Pipe msgs through 'formail' so they are stored properly
     open my $pipe, "| formail >> $file"
       or die("Formail Open Pipe Error: $!");

     # Skip the msg if its over 100k
     if ($imap->size($msg) > 100000) {
       $imap->delete_message($msg);
       next;
     }

     # Send msg through file pipe
     $imap->message_to_file($pipe, $msg);

     # Close the messgae pipe
     close $pipe
       or die("Formail Close Pipe Error: $!");

     # Delete each message after downloading
     $imap->delete_message($msg);

     # If we are just testing and want to leave
     #  leave the messages untouched, then we
     #  can use the following line of code
     # $imap->deny_seeing($msg);
   }

   # Expunge and close the folder
   $imap->expunge($box);
   $imap->close($box);
 }

 # We're all done with IMAP here
 $imap->logout();

Sys::Hostname

Friday, January 19th, 2007

Description: Sys::Hostname is a relatively small, but very useful module. Just as the module name describes, it gets your system’s hostname. To paraphrase the module’s POD documentation, it will try every conceivable way to get the hostname of the current machine.

CPAN: Sys::Hostname

Example:
The one and only use for this module.

# Always be safe
use strict;
use warnings;

# Use the module
use Sys::Hostname;

# Get the hostname
my $host = Sys::Hostname::hostname();

# The above line can also be written as
#my $host = hostname;

print "You are on: $host\\n";

HTML::Entities

Thursday, January 18th, 2007

Description: When taking user input through any number of forms, there could be characters that you aren’t expecting. This is exactly what HTML::Entities was designed to handle. When getting the user input, it converts it into a form that can help in mitigating certain types of web based scripting attacks.

CPAN: HTML::Entities

Example 1:
The general example of using

1
encode_entities()

is probably also the most common. It basically says to encode everything in the string that its possible to encode.

# Always be safe and smart
use strict;
use warnings;

# Use the module
use HTML::Entities;

 my $html = "bad stuff here&#$%";
 $html = encode_entities($html);
 print "HTML: $html\\n";

__OUTPUT__
HTML: bad stuff here&#0

Example 2:
This is the slightly more specific example as it uses only specific sets of characters as the “unsafe” characters.

# Always be safe and smart
use strict;
use warnings;

# Use the module
use HTML::Entities;

 my $html = "bad stuff here&#$%";
 $html = encode_entities($html, "\\x80-\\xff");
 print "HTML: $html\\n";

__OUTPUT__
HTML: bad stuff here&amp;amp;#0

Example 3:
This is an example of

1
decode_entities()

which does the reverse. It checks the string to see if there are any HTML encoded characters and decodes them into their Unicode equivalent. This is the general version of

1
decode_entities()

which is similar to the version of

1
encode_entities()

demonstrated in Example 1.

# Always be safe and smart
use strict;
use warnings;

# Use the module
use HTML::Entities;

 my $html = "encoded: bad stuff here&amp;#0";
 $html = decode_entities($html);
 print "Unicode: $html\\n";

__OUTPUT__
Unicode: encoded: bad stuff here&#0

Mail::Sender

Wednesday, January 17th, 2007

Description: This is probably one of the modules that I use most frequently. I commonly write reporting and statistic generating scripts. When the data is finished being crunched, I then dump it into a scalar and send it off in an email. This is the module that does my dirty work for me.

CPAN: Mail::Sender

Example 1:
This is probably the most common implementation of Mail::Sender that I use. I generally build up what is going to go in the $EMAIL variable throughout the script and then eval it to ensure it gets put into the message.

# Always be safe
use strict;
use warnings;

# Use the module
use Mail::Sender;

# Remove Mail::Sender logo feces from mail header
$Mail::Sender::NO_X_MAILER = 1;

my $EMAIL = "This is the body of the email here.\\n";

  eval {
   # Create the anonymous Mail::Sender object
   (new Mail::Sender)->MailMsg(
   {
     smtp => "mail.mydomain.com",
     from => "\\"Postmaster\\" <postmaster\\@mydomain.com>",
     to   => "\\"Eric Lubow\\" <me\\@mydomain.com.com>",
     cc   => "\\"Tech Support\\" <tech\\@mydomain.com>",
     subject => "Test Email",
     msg  => "$EMAIL"
   })
     # Show the Mail::Sender error since $! isn't set here
     or die "Error Sending Mail: $Mail::Sender::Error";
  };

Example 2:
This example sends a mixed multipart message, with text in HTML and alternative text in plaintext. If the receiving user’s email client can read HTML messages, then the HTML portion of the message will be shown. Otherwise, the plaintext (alternative) will show. The iterative loop sends the email message to as many users as are in the array. The script just provides a qw (quote words) statement to be used in the loop. Your best bet would be to create an array of email addresses and iterate over the array:

 my @emails = ["eric@mydomain.com","techs@mydomain.com"];
 for my $rcpt (@emails) {
   ...
 }

Note: In this example, I have also included a subroutine to create a message boundary. I don’t particularly have anything major against the one’s that are generated by default, I just think they give away a little too much information for my liking. Mine is slightly more random.

# Always be safe
use strict;
use warnings;

# Use the module
use Mail::Sender;

# Remove Mail::Sender logo feces from mail header
$Mail::Sender::NO_X_MAILER = 1;

 for my $rcpt (qw( me@mydomain.com tech@mydomain.com ) ) {
   my $sender = new Mail::Sender
    { smtp => '127.0.0.1',
       from => "$from_name <postmaster\\@mydomain.com>",
       boundary => make_boundary()
    }
    or die "Error in mailing: $Mail::Sender::Error\\n";

   # Begin the message, tells the header what message type
   $sender->OpenMultipart(
     { to        => "eric\\@mydomain.com",
        subject   => "Test Email",
        headers   => "Return-Path: postmaster\\@mydomain.com\\r\\n",
        multipart => "mixed",
     })
     or die "Can't Open message: $sender->{'error_msg'}\n";

     # Change the content-type
     $sender->Part( { ctype => 'multipart/alternative' });

     # Put the plain text into the email (aka the alternative text)
     $sender->Part(
       { ctype       => 'text/plain',
         disposition => 'NONE',
         msg          => "This is a test message.\n\nHere is the plaintext.\\n"
       });

     # Put the HTML text into the HTML (what SHOULD be displayed)
     $sender->Part(
       { ctype       => 'text/html',
         disposition => 'NONE',
         msg         => "This is a <B>TEST</B> message.\\n<br>\\n"
       });

     # The message isn't sent until it's Close()'d
     $sender->Close()
       or die "Failed to send message: $sender->{'error_msg'}\\n";
 }

#######################################################
# Function: Creates a random message boundary
# Parameters: None
# Return: Boundary
# Notes: Bounaries are 43 characters in length
#######################################################
sub make_boundary {
  my ($boundary, $char, $wanted) = ('','',43);

  open R, '<', "/dev/urandom";
  while ($wanted) {
    read (R, $char, 1)
      or die "Couldn't read from /dev/urandom: $!\n";
    if ($char =~ /[A-Za-z0-9]/) {
      $boundary .= $char;
      --$wanted;
    }
  }
  close(R);

  return $boundary;
}

IO::Socket::INET

Tuesday, January 16th, 2007

Description: When I need to interact with the raw IO of telnetting to a port or creating a hand rolled implementation of my own service, I use IO::Socket. My most recent endeavor was for a need to check weather or not services were running on a regular basis. I will show some excepts from the code later on in this post.

Although IO::Socket::INET is just a frontend for a good number of Perl’s builtin functions, I find it handy as it is generally a little more sane.

CPAN: IO::Socket::INET

Note: IO::Socket::INET is a subclass of IO::Socket.

Example 1:
This example is the socket portion of a script that checks to see if certain daemons are alive. It does this by connecting to the port that they should be listening on. If it receives a response, then the daemon is alive, if not, it restarts the daemon and tries contacting it again. As you can see below, the response itself doesn’t matter, just that there is a response being received.

# Always be safe and smart
use strict;
use warnings;

# Use the module
use IO::Socket;

 # Prototype the socket
 my $socket = new IO::Socket::INET(
                   PeerAddr => "localhost",   # Hostname/IP
                   PeerPort => "smtp(25)",   # Service (Port)
                   Proto    => "tcp",            # Protocol
                   )
   or die "Socket bind error: $!";

 # Create the socket
 $socket
   or die "Socket error: $!";

 # Close the socket
 close $socket
   or die "Socket close error: $!";

Example 2:
On the other side of the fence, we can create a listening socket that can act as a server. If you run this little script and then connect to the specified port it will say something along the following:

1
Welcome 127.0.0.1 to a simple socket server.

The server script will listen indefinitely (or at least until you press CTRL-C to make it exit). To test out the script and ensure you receive something similar to the above response (with your IP instead of 127.0.0.1), from the linux command prompt, type the following (replace with your IP and port):

1
$ telnet localhost 12345
# Always be safe and smart
use strict;
use warnings;

# Use the module
use IO::Socket;

 # Listen port
 my $port = 12345;

 # Prototype the socket
 my $server = new IO::Socket::INET(
   Listen   => SOMAXCONN, # Max connections allowed by system
   Reuse    => 1,               # Reuse connections
   LocalAddr => "localhost", # Listen hostname
   LocalPort => $port,        # Listen port
   Proto    => "tcp",           # Listen protocol
 ) or die "Socket bind error: $!";

 # Listen for the client until we get a CTRL-C
 while (my $client = $server->accept()) {
   # Force the data out of the stack
   $client->autoflush(1);

   # Say hello to my little client
   print $client "Welcome ". $client->peerhost ." ".
                 "to a simple socket server.\n";
 }

 # Close the server when we are done
 close $server
   or die "Socket close error: $!";

File::Pid

Thursday, January 11th, 2007

Description: Consistantly writing programs that either act as daemons or take a long time to run depending on the input, I find it necessary to track weather or not they are still running. Lots of programs do this and its generally called state or status tracking. One of the most common ways to do this is to use a pid file.

The most common method is to create a file with the naming scheme program_name.pid. The contents of the file is the pid of the program. Then at the conclusion of the program, the file is removed. The pid file is generally stored in the OS’s state directory (in linux). Generally being a Debian or Ubuntu, the state information is stored in the /var/run/ directory. I also frequently use EnGarde Secure Linux which also has a state directory of /var/run/.

CPAN: File::Pid

Note: In the spirit of TIMTOWTDI, the process itself isn’t overly complex. To illustrate that, I will show one method of accomplishing this goal without using a Perl module. I will also be using the Perl special variable $$. To quote the Perl Special Variables page:

  • $PROCESS_ID
  • $PID
  • $$

    The process number of the Perl running this script. You should consider this variable read-only, although it will be altered across fork() calls. (Mnemonic: same as shells.)

    Note for Linux users: on Linux, the C functions getpid and getppid() return different values from different threads. In order to be portable, this behavior is not reflected by $$, whose value remains consistent across threads. If you want to call the underlying getpid, you may use the CPAN module Linux::Pid.

  • As you will likely note, although potentially less portable across OS’s, using File::Pid is much cleaner and easier.

    # Declare your variables
    my $pid_file = "/var/run/myprog.pid";
    local *PIDFILE;
    
    # Check for the PID file's existance
    if (-e $pid_file) {
      die ("Program already running or ended prematurely\\n");
    }
    
    # Create the PID file
    # Use the 3 argument form of open for safety
    open PIDFILE, ">", $pid_file;
    print PIDFILE "$$\\n";
    close PIDFILE;
    
    # XXX - Program here
    
    # Remove PID file
    unlink $pid_file
      or die "Error unlinking $pid_file: $!";
    

    Example 1:
    Using the basic example of just creating the PID file, checking if the program is already running, and removing the PID file, let’s take a look at the OO (Object Oriented) example:

    # Always be safe & strict
    use strict;
    use warnings;
    # Use the module
    use File::Pid;
    
     # Create the PID object
     # Ensure you put a name that won't clobber
     #   another program's PID file
     my $PID = File::Pid->new({
       file  => '/var/run/myprog.pid',
     });
    
     # Write the PID file
     $PID->write;
    
     # Check for the previous instance
     #  and die if PID file already exists
     if (my $oldPID = $PID->running()) {
       die "myprog already running: $oldPID\n";
     }
    
     # XXX - Program here
    
     # Remove the PID file
     $PID->remove;
    

    File::Find

    Wednesday, January 10th, 2007

    Description: File::Find is a pretty straightforward and useful module. I often find myself needing to hunt down a bunch of files or parse through a particular grouping of files. Because of TIMTOWTDI, I usually choose to use File::Find based on its ease of use.

    CPAN: File::Find

    Example 1:
    Being a System’s Administrator, I am usually hunting for something in a logfile. Therefore, I like to parse through all the logs for a particular program or daemon that I can get my hands on.

    # Always use these
    use strict;
    use warnings;
    # Use the module itself
    use File::Find;
    
    # Declare your variables
    my @files;
    my $dir = "/var/log/";
    
     # Actually find the file
     #  -f tests to see if it is a file (not a device or symlink, etc)
     #  Matches the RE for "mail.log.*"
     #    in the directory $dir
     find(
       sub { push @files, $File::Find::name if -f && /mail\.log.*/ },
       $dir);
    
     # Iterate over the files and print those found
     for my $file (@files) {
       print "File: $file\\n";
     }
    

    Email::Find

    Tuesday, January 9th, 2007

    Description: Email::Find is a module for finding a subset of RFC 822 email addresses in arbitrary text. The addresses it finds are not guaranteed to exist or even actually be email addresses at all, but they will be valid RFC 822 syntax. Email::Find will perform some heuristics to avoid some of the more obvious red herrings and false addresses, but there’s only so much which can be done without a human. (Note: Taken from the author’s description)

    CPAN: Email::Find

    Example 1:
    I often find myself with a list of email address in an Excel spreadsheet or on an email that someone sent to me with a list of names. Normally I have to take this list and resend a message to the recipients without allowing all the addresses to be seen. Since according to RFC 2822, there are multiple implementations of how a message with BCC recipients can be sent, I find it is easier to break the recipients down myself and have them presented to me in a way that I can use them in a quantity in which they are useful to me.
    Excerpt from RFC 2822:

    The “Bcc:” field (where the “Bcc” means “Blind Carbon Copy”) contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message. There are three ways in which the “Bcc:” field is used. In the first case, when a message containing a “Bcc:” field is prepared to be sent, the “Bcc:” line is removed even though all of the recipients (including those specified in the “Bcc:” field) are sent a copy of the message. In the second case, recipients specified in the “To:” and “Cc:” lines each are sent a copy of the message with the “Bcc:” line removed as above, but the recipients on the “Bcc:” line get a separate copy of the message containing a “Bcc:” line. (When there are multiple recipient addresses in the “Bcc:” field, some implementations actually send a separate copy of the message to each recipient with a “Bcc:” containing only the address of that particular recipient.) Finally, since a “Bcc:” field may contain no addresses, a “Bcc:” field can be sent without any addresses indicating to the recipients that blind copies were sent to someone. Which method to use with “Bcc:” fields is implementation dependent, but refer to the “Security Considerations” section of this document for a discussion of each.

    To accomplish this, I use variations of the following simple script:

    # Always use these
    use strict;
    use warnings;
    # Use the module itself
    use Email::Find;
    
    # Declare your variables before using them
    my (@emails, $file, $counter);
    # Limit the number of email addresses per line
    my $max = 20;
    
    # Code block to slurp the file on $ARGV[0]
    {
      # Slurp the file by changing the Perl special variable
      local $/ = undef;
      local *FILE;
      open FILE, '<', "$ARGV[0]"
        or die "File Open Error: $!";
      $file  = <FILE>;
      close FILE
        or die "File Close Error: $!";
    }
    
      # Prototype the pushing of all the addresses
      #  found onto an array leaving the original text
      my $finder = Email::Find->new(sub {
            my ($email, $orig_email) = @_;
            push @emails, $email->format;
            return $orig_email;
            });
      # Actually push the addresses found in $file
      $finder->find(\$file);
    
      # Loop and print $max email addresses per line
      #  separated by a semi-colon ';' and then each
      #  line separated by two carriage returns '\n'
      for my $address (@emails) {
        $counter++;
        print "$address;";
        print "\n\n"
          if $counter == $max;
        $counter = 0
          if $counter == $max;
      }
    

    Perl Modules Introduction

    Monday, January 8th, 2007

    Before I go into any modules, I think I should explain what I am doing and why I am doing it. And although I am sure that this is done elsewhere and I am not a fan of reinventing the wheel, I am a fan of making my own life easier and hopefully other’s lives as well.

    I often find myself using / reusing the same modules for small scripts. Either they are Perl one-liners or very short scripts to accomplish a semi-common task. Rather than going through and figuring out how I used the module so effectively in the previous instance, I have resorted to storing examples of how I implement various modules in my local CVS repository. Although the whole versioning and tagging system allows me the flexibility of using more than 1 example per module, it is also somewhat restrictive in its ability to allow for search (unless you checkout the whole repository and grep or other overkill or tedious methods).

    Then I decided that a good way to do this would be to use a blog. This is the method I chose for a few reasons.

    1. Searchable
    2. I can easily search for the module I want to use taking advantage of either Google‘s index of my site (or another search engine or blog search engine). I can also easily search it using the internal searching methods of the blog.

    3. Central Location
    4. As I said before…although I am sure that there are other places that do this (including the POD source of many modules and CPAN), I want a central location with easy to understand code.

    5. Everyone Else
    6. There are many other’s out there who sometimes don’t understand the code in the POD or in some other code examples. Even larger code repositories and search engines like Krugle are still a little kludgey for basic examples. This also allows for people to contribute if they so desire.

    And another great thing about this is that if I get a lot of examples in here, then search engine sites and code repositories will index it and it will be useful to more than just a select few elite who read this blog.

    The general rule of this for me is to explain a little about the module, give an example or two from real life, and provide some useful comments to help explain what the code is doing. Since I don’t plan on re-inventing the wheel (as stated more than a few times), I may just copy and paste from the module author (giving credit where credit is due of course). I encourage anyone with simple enough code to provide examples at any point as well. Enjoy.