An Introduction to Perl
Course book
Lyle Hopkins
Written by Gareth Hopkins
About the course tutor
Lyle started programming from an early age on a ZX Spectrum this interest in computers continued and with the expansion of computing he has remained at the forefront of programming.
Nine years ago while at college Lyle built a business selling Perl scripts, from a directory listing package to an enquiry handler CRM the most successful product was affiliate software
AllAffiliatePro? . Lyle made the decision to focus his attention on developing
AllAffiliatePro? and continues to do so using Perl as his preferred language. Now the leader of the Perl chapter for Bristol, Lyle is considered a Perl programming guru, being invited to give lectures at local universities, and becoming actively involved in developing a qualification in the language.
Chapter 1: Getting Started with Perl - Computer set up
Windows:
ActivePerl? can be downloaded from
http://www.activestate.com/activeperl/ ensure that you select the right edition for your operating system. The installation should automatically associate .pl files with the Perl interpreter.
Linux:
Perl is included in most distributions of Linux. If you do not have the Perl package installed for your distro there will be one available, you can also download
ActivePerl? from the link above.
Setting up a web server
Windows:
If you do not have windows IIS you can download Apache from
http://httpd.apache.org/download.cgi
If you download the msi version you'll have a nice wizard to take you through the install. Providing you follow the defaults Apache will be displayed locally at
http://localhost .
Linux:
Apache is also already included with most distributions and is available at
http://localhost also. You may need to install your distro's package for this.
Chapter 2: Programming and Computers
A basic computer consists of CPU, RAM and a HDD with input devices such as keyboard and mouse, output devices such as VDU and printers.
The CPU processes requests based on the 86 instruction set. Early computers were programmed in binary a series of 0’s and 1’s. 1 byte = 8 bits of binary i.e 01001010. This made programming a lengthy process so assembly language evolved and then on to C programming.
C is the foundation for most programming languages we have today. Higher level languages such as Perl, Java and Python use richer syntax making it easier to code larger more detailed programs. A program that's hundreds of lines of C could be just tens of lines of Perl.
Chapter 3: Programming in Perl
This course is short so it's structured to be as hands on as possible. But before we can write any code, you need to understand a few basics.
Comments
To make the examples clearer we use comment tags. Anything on a line after a #, is a comment and ignored by Perl (this isn't always true).
#This is a comment
Outputting data
At this point we'll cover basic data output using
print, so that you can get hands on a writing some working code. The print statement is used in many programming languages as the means of outputting data to a variety of devices, such as your HD in the form of a file, or text onto your screen.
print 'Hello world!';
Line endings
So that long lines of code can be easily broken over several lines, or short lines of code can be put on the same line, lines of Perl code must end with a semi colon ';'. As with comments there are of course exceptions.
Running Perl scripts
Perl scripts are just text files that contain Perl code. They are most commonly saved with the file extension “.pl”. These scripts can be ran along the command line, using the Perl interpreter. Let's use the above
print example as our first program. Open a text editor such as notepad, word processors such as Word and
WordPad? are not suitable as they try to format the text. Perl scripts should always start with the path to Perl. This is known as the shebang line. In these exercises we'll be invoking Perl directly so it's not technically needed, but it is good practice to put it in anyway.
In your text editor type:-
#!c:/perl/bin/perl.exe
print 'Hello world!';
Save this as hello.pl within a suitable folder (such as “c:\perlscripts”). You'll see that the path to Perl uses forward slashes / as opposed to backslashes \. That is because Perl was originally developed for Unix based systems which use the forward slash for directory paths.
Now open a command prompt (usually Start->Accessories->Command Prompt), navigate to the folder where you saved the hello.pl script (“cd \perlscripts”) and run the script with the Perl interpreter (“perl hello.pl”). You should get the output “Hello World!”.
Variables
Data that you are currently working with is stored in variables. Think of variables as labelled containers. There are different kinds of variables for storing different kinds of data.
For example to define a variable in C you need to declare what type it is e.g.
Number = int
Letter = char
Word = varchar
Luckily Perl's variables aren't as strictly typed.
Scalars
In Perl integers, strings, etc, do not have to be defined separately and are more simply defined as Scalars e.g.
$number = 10;
$char = 'c';
$huge = 'pages of information';
Scalars are denoted by the $ sigil. Perl has variables that can be global; allowing all parts of the program to access them, or local; allowing only certain blocks of code access them.
A global variable is defined as
our $name = 'xyx';
Whereas a local variable is
my $name = 'xyz';
It's good practice to have all or most your variables as local variables.
Scalars that have been initialized but not assigned a value have a special value known as NULL. Perl calls NULL
undef, for undefined.
undef is not the same as an empty string.
my $scalar; # $scalar will contain undef
my $empty = ''; # $empty will contain an empty string
my $undef = undef; # $undef will contain undef
† The 'our' syntax for defining global variables was introduced with Perl v5.6. Some people still prefer the old method of declaring globals with:
use vars qw( $LIST @OF %GLOBALS );
Using Scalars
Let's update our hello.pl script to use a scalar to contain the message:-
#!c:/perl/bin/perl.exe
my $message = 'Hello world!';
print $message;
Working with Scalars
There are different ways of working with Scalars. Perl is well known for TIMTOWTDO (There is more than one way to do it). Here are some examples of common things you'll want to do with Scalars.
Interpolation
Our previous hello.pl example uses single quotes '. Single quotes do not interpolate Scalars. Such that the code
my $name = 'Lyle';
print 'Hello $name';
Would output the text “Hello $name”.
Double quotes do interpolate, such that the same code with double quotes
my $name = 'Lyle';
print “Hello $name”;
Would give you “Hello Lyle”.
Joining strings
Strings can be joined with double quotes, the
join function, or by using the dot '
. ' operator.
my $start = 'Hello';
my $end = 'World';
my $joined = “$start $end”; # Same
$joined = join( ' ', $start, $end ); # Same
$joined = $start . ' ' . $end; # Same
Repeating strings
You can also repeat strings with the
x operator.
print 'Hi!' x 5;
Would display “Hi!Hi!Hi!Hi!Hi!”.
Working with numbers
You have all the normal math operators. Examples:-
print 1 + 1; # Displays 2
my $multi = 5 * 5; # $multi contains 25
my $div = 5 / 5; # $div contains 1
Arrays
Defined using the @ symbol in front of the array name, arrays store a list variables with numbered locations starting at 0. e.g
my @array = (‘one’, ‘two’);
stores ‘one’ at location 0 and ‘two’ at location 1. This is an important thing to note with a lot of computer arithmetic, numbering generally starts at 0.
To add a variable to the end of any array you can use the
push command.
push( @array, ’three’ );
or simply use:
@array = ( @array, ’three’ );
To join an array
my @join = ( @array1, @array2 );
To take an item off the end of an array, use
pop.
my $item = pop( @array );
So
push and
pop are a pair of functions that deal with adding/removing from the end of an array. Their counterparts are
unshift and
shift, that deal with adding/removing from the start of an array.
shift takes the first item off of an array.
my $item = shift( @array );
and
unshift puts it back on
unshift( @array, 'zero' );
To access a value in an array you need to reference its location e.g
my @array = (‘one’, ‘two’,’three’);
my $item = $array[1];
$item will contain 'two', if no value is returned you get
undef. Note that when obtaining an arrays value you use $ rather than @ and square brackets []. This is because you are accessing a single Scalar value form the array, not the whole array.
To sort an array
@array = sort @array;
The default sort is an ASCII one, so A-Z goes before a-z. We'll cover more on sorting later.
Getting input from the user
There are different ways of getting input from a user. From command line arguments to sockets. Here are a couple of common methods.
Command line arguments
Perl has a special variable named
@ARGV. It's an array containing all of the parameters passed into the script when it's been called from the command line. For instance the script:-
#!c:/perl/bin/perl.exe
print $ARGV[0];
Would print the first parameter passed in. So if called with “perl script.pl Hello” it would display “Hello”. If called with “perl script.pl Hello Lyle” it would still only display “Hello”. This is because it's only printing the first parameter passed. You could use parenthesis to make the first parameter contain both Hello and Lyle, such as 'perl script.pl “Hello Lyle”' would print “Hello Lyle”.
STDIN file handle
STDIN stands for 'Standard Input”. Generally speaking, all Unix derived languages will have a STDIN, STDOUT 'Standard Output' and STDERR 'Standard Error'. They are treated as file handles that you can either read from, or write to. You've already used STDOUT, by default print goes to STDOUT, so the following lines are the same:-
print “Hello”;
print STDOUT “Hello”; # Same
You can read from STDIN using the readline command, although Perl provides shorthand in the form of <FILEHANDLE>, such that:-
my $name = readline(*STDIN);
my $name = <STDIN>; # Same
It's uncommon to use readline, so stick with <STDIN>. You'll notice that in the readline example, STDIN has a * sigil, this is because to pass file handles into functions you must pass the whole GLOB. I'm not covering GLOBs here, for now think of them as another kind of variable.
The example code above will pause the program and wait for user input, once the user hits enter the program will continue and $name will contain whatever they typed.
Conditionals
Things would be pretty boring if programs just went in a straight line all the time. Conditionals allow the software to make decisions based on variables, often ones that have been input. Perl offers
if,
elsif,
else and for convenience
unless.
if
The if statement allows you to run a block of code if a condition is true. They are in the format:-
if ( CONDITION ) {
CODE
}#if
You'll notice the use of curly brackets again. This time they surround the block of code that is to be run if the condition is true. The small comment on the end #if is a personal touch and not required. In larger programs you can have many code blocks within code blocks, a simple comment on the end bracket can help you keep track of where they started.
In singular context, Perl sees anything that isn't undef, 0, 0.0 or '' (empty string), '0' (string containing 0) or an empty list as true. Examples:-
if ( 0 ) { } # False
if ( 1 ) { } # True
if ( 0.0 ) { } # False
if ( '' ) { } # False
if ( 'text' ) { } # True
if ( undef ) { } # False
You can also reverse this with
not or
!, such as:-
if ( ! 0 ) { } # True
if ( not 1 ) { } # False
You can also make comparisons or check if an operation or function returns a true value:-
if ( 0 == 0 ) { } # True
if ( 1 == 0 ) { } # False
Note that for comparisons you need to use == rather than just =. This is because = is used for an assignment. Example:-
# Correct way
my $value = 1;
if ( $value == 1 ) { } # True
# Wrong way
if ( $value = 0 ) { } # True
Both examples return true. This is because the second one assigns 0 to the scalar $value which is a successful operation returning true.
!,
>,
< can also be used:-
if ( 0 = 0 ) { } # False
if ( 1 > 0 ) { } # True
if ( 0 <= 0 ) { } # True
When comparing strings you use the
eq and
ne syntax instead (equals, not equals respectively):-
if ( 'a' eq 'b' ) { } # False
if ( 'a' ne 'b' ) { } # True
You also have OR, ||, AND, &&. OR and || do basically the same thing, as do AND and &&. There are subtle differences in preference, but I won't be covering them as the vast majority of the time they are interchangeable.
if ( 'a' eq 'b' || 1 > 0 ) { } # True
if ( 'a' ne 'b' && 1 < 0 ) { } # False
else
You may also use the else statement with if, allowing to to do one thing or the other. Such as:-
if ( $name eq 'Lyle' ) {
print 'Thanks for teaching us Lyle';
}#if
else {
print “Hello $name”;
}#else
elsif
Often 'else if' or 'elseif' in other languages, shortened to
elsif in Perl. It allows you to run another condition only if the original
if is false. You can have many
elsif statements as you want, often you end with a
else. Such as:-
if ( $name eq 'Lyle' ) {
print 'Thanks for teaching us Lyle';
}#if
elsif ( $name eq '' ) {
print “Please input your name”;
}#elsif
else {
print “Hello $name”;
}#else
unless
For general convenience and to make things read easier,
unless is provided as an alternative to
if not.
if ( not( 9 > 10 ) ) { } # True
unless ( 9 > 10 ) { } # Same
Random numbers
Random numbers can be useful for many things. Later we'll use this to create a basic guessing game. Perl has the
rand function, that returns a random decimal number between 0 and the number you give it. For example:-
print rand(10);
Will typically display a number between 0 and 9.999999999999999. A lot of the time you'll be interested in whole numbers (integers). The
int function returns only the integer portion of a whole number. So the previous example can be updated to:-
print int( rand(10) );
Which will now display between 0 and 9.
Hashs
A Hash is an associative array with key and value pairs. It's defined using the % sigil. E.g.
my %dogs = ( bolt => 'male', cassie => 'female' );
my $sex = $dogs{'cassie'}; # returns the value 'female'
Note that as with arrays, when you are accessing a single value you use $ rather than %, but with hashes you use curly brackets {}.
To add a single key/value pair to a hash you do:-
$dogs{'barley'} = 'female';
When working with hashes you have three useful functions:
keys,
values and
delete.
keys returns a list of the hash's keys:-
my @keylist = keys %dogs; # @keylist would contain 'bolt', 'cassie' & 'barley'
Remember that an array is a list of values, so
keys returning a list of the hash's keys is effectively an array. You can in fact use
keys wherever you'd normally use an array, such as in
for and
foreach loops that we cover later.
values works in a similar way, but returns a list of the hash's values.
my @valuelist = values %dogs; # 'male', 'female', 'female'
An important thing to note is that while arrays are in a fixed order, hashes are not. So the order in which
keys and
values return will not be the same in which you put in. The above example could also return 'female', 'male', 'female' or 'female', 'female', 'male'. In programming terms this is often referred to as a bag (jumbled) instead of a list (ordered).
delete lets you remove a key/value pair from the hash:-
delete $dogs{'barley'};
Loops
Loops allow you to repeat pieces of code over and over, usually until a variable has a certain value, or the user gives certain input. Perl has several looping constructs, most commonly
for /
foreach,
while,
until.
for/foreach
for and
foreach are interchangeable and work in exactly the same way. Many Perl programmers prefer foreach for things like looping through an array, simply because it reads better. Personally I use
for when it's a classical for loop counting up an integer, such as:-
for ( my $int = 0; $int < 10; $int++ ) {
# CODE
}#for
I use
foreach for arrays, which includes the lists returned by
keys and
values.
foreach my $key ( keys %hash ) {
print “$key = $hash{$key}\n”;
}#foreach
Will print the key and hash value from the above example.
foreach my $elem ( @array ) {
print “$elem\n”;
}#foreach
Will display all the elements of the array.
while
while loops use a condition just like
if statements do. The block of code will be repeated while the condition is true.
while ( 1 ) {
# infinite loop
}#while
until
The counterpart to while is until. The code block will be run until the condition is true.
my $i = 1;
until ( $i > 10 ) {
print “$i\n”;
$i++;
}#until
That example would display 1 to 10.
Task
A) Make a random number guessing game. The user has to pick a number between 1 and 20. If they pick to high it tells them 'higher', if they pick to low it tells them 'lower'. They only get 5 tries.
B) Extend the previous task to take the players name and use it in the dialogue.
C) Extend the previous task to give the player a score.
D) Extend the previous task to add new features of your own and make it more entertaining.
Task Solution
There are many different ways you can code a solution to the task. Here is an example with the steps I took to create it.
1. Prepare the file
Start the file and add comment tags for the objective
#!/perl/bin/perl.exe
# Make a random number guessing game.
# The user has to pick a number between 1 and 20.
# If they pick to high it tells them 'higher'
# If they pick to low it tells them 'lower'.
# They only get 5 tries.
Having the objectives at the top of the file helps you keep focus on what you are aiming to achieve.
2. Think out the logical steps and them as comments
It makes it a lot clearer what you are doing.
#!/perl/bin/perl.exe
# Make a random number guessing game.
# The user has to pick a number between 1 and 20.
# If they pick to high it tells them 'higher'
# If they pick to low it tells them 'lower'.
# They only get 5 tries.
# Introduce the game
# Generate a random number
# loop a maximum of 5 times
# request user guess
# Check if guess correct
# Check if guess higher
# Check if guess lower
3. Create the code
Add the actual working code between the comment tags
#!/perl/bin/perl.exe
# Make a random number guessing game.
# The user has to pick a number between 1 and 20.
# If they pick to high it tells them 'higher'
# If they pick to low it tells them 'lower'.
# They only get 5 tries.
# Introduce the game
print “Welcome to the number guessing game\n\n”;
# Generate a random number
my $number = int( rand( 20 ) );
$number++;
# loop a maximum of 5 times
my $tries = 5;
while ( $tries > 0 ) {
# request user guess
print “Guess the number between 1 and 20. $tries guesses remaining:\n”;
my $guess = <STDIN>;
# Check if guess correct
if ( $guess = $number ) {
print “Well done you guessed correct!\n”;
$tries = 0;
}#if
# Check if guess higher
if ( $guess > $number ) {
print “Lower\n”;
}#if
# Check if guess lower
if ( $guess < $number ) {
print “Higher\n”;
}#if
$tries--;
if ( $tries = 0 ) {
print “No guesses left!\n”;
}#if
}#while
Quotes
We've already covered single and double quotes. Let's go into more detail. For instance what if you are quoting text that has quotes in them? Perl treats \ as a special character, it's used as an 'escape character'. This means it can take away the functionality of other special characters such as $. It also adds special functionality to normal characters.
print “\$money”; # prints $money instead of the contents of $money
print 'It's all good'; # ERROR
print 'It\'s all good'; # Correct
print “\n”; # prints a new line
print '\n'; # prints \n
print “\t”; # prints a tab character
print “\\”; # prints a single \
You'll notice that \ doesn't add functionality when used within single quotes, but it still acts as an escape character. If you want a \ then you do two \\. The most common combinations you'll use are \n for newline, \r for carriage return and \t for tab.
Quick quotes
Sometimes using either “ or ' can be painful. For example:-
print “Lyle said \”Sometimes it's annoying\””;
print 'Lyle said ”Sometimes it\'s annoying”';
You need to use \ to escape no matter which quotes are used. For times like this quick quotes are perfect.
q acts like single quotes,
qq like double.
print qq~Lyle said ”Sometimes it's annoying”~;
print q~No interpolation $now~; # prints No interpolation $now
You can choose which character is used to surround the string. I tend to use ~ as it doesn't come up often in regular strings. There is also a quick quote for dealing with lists,
qw.
my @array = ( 'list, 'of', 'elements' );
my @array = qw( list of elements );
It saves you having to type out the list with commas and speech marks.
Reading from the Environment
Perl provides a special hash variable called %ENV that contains information about the environment your program is being run in. It's straight forward to print out the contents of %ENV in a foreach loop:-
foreach my $key ( keys %ENV ) {
print “$key = $ENV{$key}\n”;
}#foreach
%ENV is particularly useful when you are writing CGI scripts as you can get information such as browser Cookies and the users IP address.
Subroutines
When your program starts to get large, the need to break it down into subroutines becomes apparent. If you find yourself about to write the same or similar blocks of code then these belong in subroutines.
sub NAME {
BLOCK
}#sub
For example, we could expand the previous random number guessing game script to include other games. We could put each of these into a subroutine and have the user choose which game to play.
print “Select game to play:\n1) Number game\n2) Adventure game\n3) Exit\n”;
my $input = <STDIN>;
if ( $input = 1 ) {
number_game();
}#if
elsif ( $input = 2 ) {
adventure_game();
}#elsif
else {
exit;
}#else
sub number_game {
# Game code
}#sub
sub adventure_game {
# Game code
}#sub
This allows us to structure our code better, the conditionals are short and clear at the top of the script, whereas the code for the games are grouped in subroutines lower down.
Custom Functions
Perl uses the same subroutine syntax for creating functions. The special variable
@_ contains all passed in parameters and you return data with the
return function.
sub NAME {
my ( $param1, $param2 ) = @_;
BLOCK
return $value;
}#sub
So a simple function that checked an array for a certain string:-
sub check_array {
my ( $string, @array ) = @_;
my $found = 0;
foreach my $item ( @array ) {
$found = 1 if ( $item eq $string );
}#foreach
return $found;
}#sub
my $exists = check_array( 'string', @array );
Teaching yourself more
Online
Perl Mongers –
www.pm.org, you local group is Bristol and Bath Perl Mongers, ran by Lyle Hopkins.
http://perl.bristolbath.org
PerlMonks? –
www.perlmonks.org, you need to understand HTML in order to post, but a very useful resource if you get stuck.
Perldoc – perldoc.perl.org, online documentation for Perl commands and syntax
CPAN – Comprehensive Perl Archive Network, large collection of ready to use Perl modules for just about everything.
PerlTrain? follow on course – Heavily discounted follow on course for suitable students.
Recommended Reading
Perl Programming 3
rd Edition, July 2000, Larry Wall, Tom Christiansen and Jon Orwant published by O'Reilly
Learning Perl
CGI Programming with perl 2
nd Edition, July 2000, Scott Guelich, Shishir Gundavaram and Gunther Birznieks published by O'Reilly