PrevIndexNext
Miscellaneous Topics I
Perl is a very large subject.
In this section we cover several things that
don't quite merit an entire class with
labs, etc. This is more of a survey and
overview of things that you might need
someday. It is good to at least know that they are there.
Give each of them a try and play around a little!
perldoc and POD
Perl has very extensive online documentation.
It is all accessed via the 'perldoc' command. For example:
% perldoc perlsyn
will give you a thorough explanation of the statement syntax of Perl.
To get a sense of the totality of Perl documentation try this:
% perldoc perltoc
To get the documenation for any built-in function you can
do:
% perldoc -f print
This documentation is in a simple format called POD - Plain Old Documentation.
See full details with 'perldoc perlpod'. Here is an example of using POD
to provide external documentation for your source code. This kind of
POD is usually put after a line containing only __END__.
Anything after this special END line is ignored
when the script is run. It is processed by perldoc.
In hello.pl:
#!/usr/bin/perl
print "hello, world\n";
__END__
=head1 NAME
hello
=head1 SYNOPSIS
This is the B<simplest> of programs.
'perldoc hello.pl' will show this:
NAME
hello
SYNOPSIS
This is the simplest of programs.
There are several POD commands like =head1. They all begin with =.
A blank line must precede and follow the commands.
split and join
'split' takes a regular expression and a scalar and returns an array.
my $line = "helen:34:f:123 main st:san francisco:90034";
my @fields = split /:/, $line;
print "age: $fields[1]\n"; # 34
It does a global search
in the scalar for the regular expression and
returns the array of the strings BETWEEN the
places it matched. Another example:
my $line = "hello, blah, oops , more,t";
my @fields = split /\s*,\s*/, $line;
# @fields gets: hello blah oops more t
If you give an empty regex to split it
will return an array of all of the individual characters in the string.
my $s = "hello there";
my @chars = split //, $s;
print "@chars\n";
# this prints:
h e l l o t h e r e
The opposite of split is 'join'.
@nums = (1, 4, 32, 2);
$numstr = join ":", @nums; # 1:4:32:2
When an array is interpolated, Perl is using 'join'
to put spaces between the elements of the array.
Input Record Separator
The special variable $/ is used to
alter how lines are read from a file handle.
It tells Perl what string (unfortunately not a pattern/regexp) to
use to indicate the 'end of line'.
Setting it to something other than the default "\n"
allows you to read "paragraphs" or "chunks" at a time
rather than lines at a time. Sometimes the unit of
a line is not what you really want.
For example, Setting it to "\n\n" will cause a program to read
until it sees an entirely blank line. It will return
a multi-line string with embedded newlines.
Setting $/ to 'undef' allows you to read an entire file
in one fell swoop (because you will never encounter the undef value).
Here is an example:
my $picture;
{
local $/;
open IN, "pic.jpg" or die;
$picture = <IN>;
close IN;
}
The use of 'local' above will cause $/ to be set
to 'undef' for the <IN>. When the block is exited
$/ will revert to its former value.
File Tests
Asking whether a file is readable or executable
or whether it exists at all is very simple in Perl.
if (-r $fname) {
print "$fname is readable\n";
}
if (-e $fname) {
print "$fname DOES exist\n";
}
There are many letters to put after the dash.
Check the documentation at "perldoc -f -X".
Useful ones include:
r readable
w writable
x executable
d directory
e exists
T text file
B binary file
M time since last modification (in fractional days)
File and Directory Manipulation
Perl's heritage is from the Unix operating system.
Nowhere is this more clear than in the names
of the built in functions for manipulating files
and directories.
chmod
chdir
mkdir
rmdir
chown
unlink (rm - delete a file)
rename (mv)
With these functions you can manipulate files
much like you would from the Unix command line.
There are also these useful platform independent modules in the
standard library shipped with Perl:
File::Copy
File::Basename
File::Spec
File::Find
The last one enables easy recursive perusing of an
entire directory structure. See full details with "perldoc File::Find".
Here's an example that will lower case the name of all
text files in a directory heirarchy:
use File::Find;
find(\&lower, '.');
sub lower {
rename $_, lc if -f && /\.txt$/;
# cryptic or clear?
}
By the way, 'lc' is lower case (HEllo => hello),
'uc' is upper case (helLO => HELLO),
and 'ucfirst' is first char upper case (helLO => HelLO).
One Liners
At the shell prompt you can try out little snippets of Perl code
to see how they work.
% perl -e 'print ucfirst "helLO", $/'
It's best to use single quotes after the -e (e for execute).
Note that $/ (see the Input Record Separator above) is a
newline by default and is often easier to type than "\n".
Dates and Times in Perl
Perl has several ways to deal with time.
The lowest level is this:
my $t = time; # get current time
This is the current time in seconds since
January 1, 1970.
For details about day, month, year, etc use
localtime.
my ($sec, $min, $hour, $mday, $mon,
$year, $wday, $yday, $isdst ) = localtime(time);
See "perldoc -f localtime" for details.
There is a function named 'timelocal' that is the inverse
of localtime. It lives in a separate module named Time::Local
which you need to 'use':
use Time::Local;
my $time = timelocal($sec, $min, $hour, $mday, $mon, $year);
See the full details with "perldoc Time::Local".
The module DateTime (and many associated modules) will do
everything you ever wanted to do with dates and times.
Note, however, this truth:
If you have a date in your program
you have a bug in your program.
Random Numbers in Perl
The 'rand' function is all you need for generating random numbers.
my $r = rand 10;
This gives a random real (fractional) number from
0 up to but not including 10. To generate a random
dice roll of 1 to 6:
my $roll = int(rand 6) + 1;
The function 'int' will chop off the
fractional portion leaving only the integer
from 0 to 5.
Or to choose a random element of an array:
my $x = $nums[ rand @nums ];
@nums is in scalar context so will yield the
size of the array.
And "rand @nums" is in integer context
so there will be an implied int( ).
If you understand this, you have come a long ways to
understanding the idea of context sensitivity in Perl!
splice
There are the functions shift, unshift,
push and pop for dealing with the ends
of arrays. 'splice' does everything you
would ever want in the middle of the array.
my @nums = (1, 3, 5, 7, 9, 11);
my @mid = splice @nums, 2, 3, 4, 6;
print "@nums\n"; # 1 3 4 6 11
print "@mid\n"; # 5 7 9
See full details with "perldoc -f splice".
Process Management
The 'system' function will execute an external program for you.
system "/usr/bin/tar cvf /tmp/alltxt.tar *.txt";
On Unix you can give it any shell command (including
redirection and pipelines).
system "who | grep me | wc -l >/tmp/count";
Two other ways of doing this:
my $count = `who | grep me | wc -l`;
Note the backquotes.
They deliver the STDOUT of the process into the scalar.
Or a line by line approach:
open IN, "who|" or die "cannot execute who\n";
while (<IN>) {
next unless /me/;
++$count;
}
close IN;
This special parameter to 'open' effectively executes an arbitrary pipeline
and reads from the standard output of it. You can also write to
a pipeline.
Nice!
The Environment
Environment variables are available to
a Perl program by way of the %ENV hash:
# show all environment variables:
for my $v (sort keys %ENV) {
print "$v\t$ENV{$v}\n";
}
If you put a new value into %ENV
it will be seen by any subsequent program
you run with 'system' or backquotes.
A Simple Database
Built into Perl is a very nice mechanism for
keeping hashes on disk in a simple (but very
useful) key-value database.
dbmopen my %ages, "ages", 0644 or die "can't make ages dbm file";
$ages{Jon} = 53;
$ages{Pam} = 34;
$ages{Harry} = 2;
It looks like this data is going into
a normal hash in memory but in actuality it is
going to a file on your hard disk!
You can quit the program and later do this:
dbmopen my %ages, "ages", 0644 or die "cannot open ages\n";
print $ages{Harry}; # prints 2!
PrevIndexNext