Search:  
Gentoo Wiki

A_Practical_Perl_Guide

Contents

What is this?

  • an illustrated guide on Perl's capabilities, caveats, and unexpected behavior. If you hate to read documentation then this guide is for you.
  • not a reference
  • not a complete guide
  • not too suitable for non-programmers

What is Perl good for?

Mainly: system administration tasks like parsing files etc. IMHO (and in many others' opinions) it fills the gap between tasks that can be done on the command line by some shell interpreter like BASH and tasks that require to create whole applications. Of course, you can pretty well use Perl for larger projects, but you'll also need to actually master Perl for that purpose pretty well.

Want a Perl script example? See here.

General Notes

  • 'if (...) cmd;'
    does not work. Use
    'if (...) {cmd;}'
    instead. The same applies to loops.
  • Functions either return scalars or lists. They cannot return hashes. Instead return the reference to a hash: “return \%hash;”. The hash entries can then be directly accessed via “some_func()->{$key}”.
  • For doing crazy things like storing hashes in arrays look at “man perldsc”.
  • A complete perl documentation is available via 'man perl'.
  • IMHO the most important perl documentation parts are perlfunc, the perl function reference, and perlop, both accessible from within any shell via the 'man' command.

Local Variables

Code: local variables
$var = 0;
{
  $var = 1;
}
# '$var' is now set to 1
{
  my $var;
  $var = 2;
  print $var; # prints '2' to the console
}
print $var; # prints '1'

Using and Defining Functions

Code: functions
#!/usr/bin/perl
some_func('some_argument');
exit;
 
sub some_func {
  # restrict variables to local execution block (here: this function definition)
  my $some_var;
  # function arguments available as array '@_'
  print $_[0]."\n";
}

Using Arrays

Code: using arrays
@some_array = (); # assign array with zero entries
# append '$some_value' to the array
push @some_array, $some_value;
# remove last element of array and store it in '$some_value'
$some_value = pop @array;
# print all array elements one by one
for ( $i = 0; $i <= $#some_array; $i++ ) { print $some_array[$i]."\n"; }
# or
foreach (@some_array) { print };
# or even..
for my $i (0..$#some_array) { print $some_array[$i]."\n";}
# print all -- the easy way
print join("\n", @some_array)."\n";
# create an array of words
@array = ("one", "two", "three");
@array = split(" ", "one two three"); # alternative solution
($one,$two,$three) = split(" ", "one two three");
my ($one,$two,$three) = split(" ", "one two three"); # same as 'my $one;...'
  • '$#some_array' denotes the index of the last element
  • '@array' is the reference to the array. Try to print it!
  • Access to the array's elements is done via '$array[$integer]'. Note the difference in the usage of '$' and '@'!

Using Hashes

One of Perl's greatest features (IMHO) is the easy access to hash tables, thereby allowing a programmer to implement quite fast processing routines in nearly no time!

Code: using hashes
undef %hash; # 'initialize' hash (make sure it is empty)
$hash{$key} = $data; # store '$data' so we may access it later by its '$key'
# 'keys %hash' gives you an array of all keys
# print a comma-separated list of all keys in the hash:
print join(",", keys %hash); 
# loop over all keys existing in the hash:
foreach $key (keys %hash) {
  print $key."\n";
}

If your keys are not unique, then you'll have to decide on how to construct buckets. In the following example '$data' is assumed to be a text string whose values we will separate within a bucket by using a comma:

Code: using hashes
undef %hash;
if(! exists($hash{$key}) ) {
  $hash{$key} = $data;
} else {
  $hash{$key} .= ",".$data;
}

Operating on Files

Reading

Code: read a text file line by line
open (FILE, '<', $filename) or die "Cannot open file";
 while(<FILE>) { # reads a line and stores it in '$_'
 	chomp; # remove new-line chars, same as 'chomp $_;'
        # do something nasty like printing it to the console...
 	print $_."\n";
 }
 close FILE;

Let us enclose the file operation in a recursively called structure:

Code: read a text file line by line
sub some_func {
   open (FILE, '<', $filename);
   while(<FILE>) { # reads a line and stores it in '$_'
 	   chomp; # remove new-line chars, same as 'chomp $_;'
 	   ...
 	   some_func();
   }
   close FILE;
 }

That will mess up things considerably because recursively called instances will use the same file descriptor 'FILE'. A correct solution would be:

Code: read a text file line by line
sub some_func {
   my $file;
   open ($file, '<', $filename);
   while(<$file>) { # reads a line and stores it in '$_'
 	   chomp; # remove new-line chars, same as 'chomp $_;'
 	   ...
 	   some_func();
   }
   close $file;
 }

Reading Program Output (Pipes)

There are a number of ways to read the output of a program. The most simplest being:

my $prog_output = `dmesg`;
print $prog_output;

For larger programs, or those that may continuously output, or for cases where you just really want a file handle you can use:

my $program='iostat -c 2';
open(PROG, '|-', $program);
while(<PROG>) {
  next unless /^\s+\d+/;
  print ;
}
close PROG;

Giving a program input (Pipes)

If you need to pass data to an external program, you can do so via filehandles similar to the above example, the main difference is you open them with a '-|':

my $program='/path/to/program';
open(PROG, '-|', $program);
print PROG "Some data you wish the program to have\n";
close PROG;

Writing to Files

open (FILE, '>', filename);
print FILE "some text\n"; # no comma!
...
close FILE;

Reading Directories

The quick and dirty way is to use globs. This is best explained with an example:

foreach (</usr/bin/*>) {
  next if ( -d $_ || -x $_);  # skip directories and executables
  print "$_ isn't executable.\n";
}

If you need or want to open a directory as a filehandle, use opendir:

opendir DIR, '/home/my';
 
while($de = readdir DIR) {
  if($de ne '.' && $de ne '..') {
    ...
  }
}
closedir DIR;

Last modified: Tue, 22 Apr 2008 06:25:00 +0000 Hits: 14,226