 |
Subroutines in Perl
|
This tutorial shows how
to create subroutines and use them in Perl. Subroutines
are pretty simple to use, and make our programs easier to read. A ‘subroutine’ is
a piece of code that gets used by our program more than once. Rather than
retype that piece of code everywhere we need it,
we put it at the end of our program, give it a name, and ‘call’ the
subroutine by that name whenever we need it.
For example, suppose we want to
get the weekday name of a specific time. In Perl, we can use the ‘time’ function to get a number which corresponds
to a number of seconds since a specific time. The ‘time’ stats
in the ‘file information’ section also use this type of number.
There is a ‘localtime()’ function that converts this sort of time
to numbers corresponding to the day of the week, the day of the year, the hour,
the minute, etc., represented by that number. For example, suppose we want
the time information represented by the current time. We could use:
$currentTime = time();
@timeInfo = localtime($currentTime);
$month = $timeInfo[4];
$weekday = $timeInfo[6];
If we want the Unix-style time that
a file was created, we have to use the ‘stat’ function,
which also returns a lot of information:
$filename = "doobie.txt";
@fileinfo = stat($filename);
$lastviewed = $fileinfo[8];
@dateinfo = localtime($lastviewed);
$daylastviewed = $dateinfo[6];
@weekdaynames = ("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday");
$daynamelastviewed = $weekdaynames[$daylastviewed];
See the next chapter for more information
about times in Perl, and the camel book or the Perl documentation for more
information about the stat function.
Right now, we’re talking about subroutines, and if you want to do the
above more than once in your program, it is a prime candidate for a subroutine.
The Basic Subroutine
You make a subroutine by putting the following at the end of your program:
sub SUBROUTINE_NAME {
SUBROUTINE CODE
}
When you call a subroutine, you
call it by the subroutine’s name, with
an ‘&’ character in front. A subroutine acts very much like
a function: if you want to send the subroutine some data, you put that data
between parentheses after the subroutine name. This data is given to the subroutine
in the array variable ‘@_’.
Here’s a program that prints
out the name of the weekday that you last looked at or changed the files
on the command line:
@weekdays = ("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
foreach $filename (@ARGV) {
$DayUsed = &getdayname($filename);
print "$filename was lasted used on a $DayUsed.\n";
}
sub getdayname {
my($filename) = shift();
my(@fileinfo,$lastused,@dateinfo,$daynumber,$dayname);
@fileinfo = stat($filename);
$lastused = $fileinfo[8] > $fileinfo[9] ? $fileinfo[8] : $fileinfo[9];
@dateinfo = localtime($lastused);
$daynumber = $dateinfo[6];
$dayname = $weekdays[$daynumber];
return $dayname;
}
First, we set up the ‘subroutine’ and called it ‘getdayname’.
When we ‘call’ the subroutine, we put an ‘&’ in
front of the name. This signals Perl that we’re calling a subroutine.
The subroutine itself consists of standard Perl code. We used two additional
functions: the ‘my’ function, which is useful only for subroutines,
tells Perl that these are ‘my’ variables, where ‘my’ refers
to the subroutine. If you have a long program, this is very useful: it tells
Perl that even if you have another variable somewhere in your program called ‘$filename’ or ‘$daynumber’,
don’t use it here! This is a different variable called ‘$filename’ that
onlyapplies inside this subroutine.
We accessed the ninth item of the stats info from the stat function. This
is the last modified time of the file, rather than the last viewed time. In
this particular program all we want is the last used, whether the file was
changed or not. So we check both those numbers and choose the largest, or most
recent, number.
The Recursive Subroutine
Here’s another use of subroutines: subroutines can call themselves. This
is called ‘recursion’. Let’s go back to our “useless
file” program, and have it call itself if the ‘file’ specified
is actually a directory. The following program will take a list of files and
directories, and print the age of the files. For the directories, it will call
itself with a list of the files in that directory. If there are any directories
inside that directory, it will call itself again, and so on until it finishes
its job!
#Syntax: useless <age in days> <list
of files to check>
$LongTime = shift(@ARGV);
& CheckOut('.',@ARGV);
print "Done!\n";
sub CheckOut {
my($DirPath,@FileList,$NewDirPath,@NewFileList);
$DirPath = shift;
@FileList = @_;
foreach $filename (@FileList) {
if (-A $filename > $LongTime) {
print "You haven't used $DirPath/$filename in a long time!\n";
}
if (-d $filename && !-l $filename && $filename !~ /\.\.?/)
{
$NewDirPath = $DirPath . '/' . $filename;
if (opendir(DIRHANDLE,$filename)) {
@NewFileList = readdir(DIRHANDLE);
closedir DIRHANDLE;
if (chdir $filename) {
&CheckOut($NewDirPath,@NewFileList);
} else {
print "\t(Cannot go into $NewDirPath)\n";
}
} else {
print "\t(Cannot open $NewDirPath)\n";
}
}
}
chdir '..';
}
About
this Tutorial
This tutorial is written by Jerry Stratton and is published
under the GNU Free Documentation License.
|