The following collection of code and comments illustrates the basics of coding Perl programs. The stroll begins with a simple "Hello World" script and adds more complex elements as we go. The comments are in bold and the Perl code is plain text.
The content is based heavily on 'A Stroll Through Perl' from LEARNING PERL, 1st edition, in a highly-condensed form and was originally used for a whirlwind, 30-minute presentation to GR.pm newbies. For in-depth, user-friendly explanations and additional examples, we highly recommend the books listed at the bottom of the page.
Output (print)
#!/usr/local/bin/perl
print "Hello,
PerlMongers!\n"; # '\n' is newline character
exit;
Input & variable
assignment (<STDIN>, =)
#!/usr/local/bin/perl
print "Hello,
PerlMongers!\n";
print "And what's
your name? "; # No newline so answer will be on same line, immediately
following output string
$name = <STDIN>;
# Assigns user-typed response to variable $name; variables start with
$; "filehandles" bracketed by <>
chomp $name;
# Strip the newline, if one exists...else, do nothing
print "Hello,
$name! Nice shirt!\n"; # DOUBLE-quotes replace variables with
their value...SINGLE-quotes do not!
exit;
Conditionals &
comparisons (if, else, eq, ==)
#!/usr/local/bin/perl
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' ) # 'eq' is string comparison; '==' is numeric comparison;
parens optional but good practice
{
# Each block of code in a loop or a conditional is surrounded by curly-brackets
print "Cool name,
come on in!\n";
}
# End of 'if' conditional
else
{
# Beginning of 'else' conditional
print "Welcome,
$name!\n";
}
# End of 'else conditional
exit;
Advanced conditionals
(elsif)
#!/usr/local/bin/perl
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' )
{ print "Cool
name, come on in!\n"; } # Brackets can be on the same line; sometimes
makes the code more readable
elsif ( $name
eq '' ) # 'elsif', not 'elseif' or 'else if'; no 'case'
statement in Perl
{ print "Fine,
don't tell me...\n"; }
else
{ print "Welcome,
$name!\n"; }
exit;
Variable assignment
#!/usr/local/bin/perl
$password = '19MAY99';
# If you don't know this date, we don't want to talk to you! : )
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' )
{ print "Cool
name, come on in!\n"; }
elsif ( $name
eq '' )
{ print "Fine,
don't tell me...\n"; exit; } # Now program exits if
name was not supplied
else
{
print "What's
your password, $name? "; #
chomp ($userpass
= <STDIN>); #
if ( $userpass
eq $password ) #
{ print "Darth
Vader lives...come on in!\n"; } #
else
#
{ print "I thought
I felt the good in you, but...\n"; exit; } #
}
print "Welcome
to Norad. Do you want to play a game?\n"; #
exit;
Arrays & loops
(@, for)
#!/usr/local/bin/perl
@password_list
= ('19MAY99','GR.pm','Perl rules'); # Arrays begin with '@'
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' )
{ print "Cool
name, come on in!\n"; }
elsif ( $name
eq '' )
{ print "Fine,
don't tell me...\n"; exit; }
else
{
print "What's
your password, $name? ";
chomp ($userpass
= <STDIN>);
for $onepass
( @password_list ) # Executes loop once for each value in
@password_list, storing the value in $onepass
{
if ( $userpass
eq $onepass )
{ $good_pass
= 1; } # 1 is interpreted by Perl as "true"; null, undefined
& zero are "false"
}
if ( $good_pass
) # If previous 'if' statement ever resolved true,
this will be true, otherwise undefined or "false"
{ print "Darth
Vader lives...come on in!\n"; }
else
{ print "I thought
I felt the good in you, but...\n"; exit; }
}
print "Welcome
to Norad. Do you want to play a game?\n";
exit;
Hashes (%)
#!/usr/local/bin/perl
%password_list
= # Hashes begin with %
(
'Ben' =>
'Kenobi', # Hashes are built of name/value pairs: KEY => (contains)
VALUE
'Darth'
=> 'Vader',
'R2D2'
=> 'C3PO'
);
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' )
{ print "Cool
name, come on in!\n"; }
elsif ( $name
eq '' )
{ print "Fine,
don't tell me...\n"; exit; }
else
{
print "What's
your password, $name? ";
chomp ($userpass
= <STDIN>);
if ( $userpass
ne '' && # Boundary condition; Unknown user
+ no password = false positive; ALWAYS DEBUG!
$userpass
eq $password_list{ $name } ) # Prefacing hash name with '$' & supplying
KEY in curly brackets returns VALUE
{ $good_pass
= 1; } # Now $good_pass is set if the appropriate
value is supplied for the key
if ( $good_pass
)
{ print "Darth
Vader lives...come on in!\n"; }
else
{ print "I thought
I felt the good in you, but...\n"; exit; }
}
print "Welcome
to Norad. Do you want to play a game?\n";
exit;
Modularizing With
Subroutines (&, sub)
#!/usr/local/bin/perl
%password_list
=
(
'Ben' =>
'Kenobi',
'Darth'
=> 'Vader',
'R2D2'
=> 'C3PO'
);
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' )
{ print "Cool
name, come on in!\n"; }
elsif ( $name
eq '' )
{ print "Fine,
don't tell me...\n"; exit; }
else
{
if ( &passwordOK(
$name ) ) # subroutine calls start with '&', accept
args in parentheses
{ print "Darth
Vader lives...come on in!\n"; }
else
{ print "I thought
I felt the good in you, but...\n"; exit; }
}
print "Welcome
to Norad. Do you want to play a game?\n";
exit;
sub passwordOK
# Subroutine definitions begin with 'sub' and subroutine name
{
# Subroutine code contained in curly brackets
my $name = shift;
# Assigns value of first argument to LOCAL variable $name (not $name
from main prog!)
print "What's
your password, $name? ";
my $userpass
= <STDIN>; # Neither of these 'my' variables will be
visible outside of subroutine
chomp $userpass;
# Can't declare & chomp at the same time
if ( $userpass
ne '' &&
$userpass
eq $password_list{ $name } ) # Subroutine stills knows about %password_list,
because it's a GLOBAL hash
{ return 1; }
# This is value returned to the subroutine call on successful match:
"true"
else
{ return 0; }
# This is value returned to the subroutine call on failed match: "false"
}
Reading external files,
advanced loops, processing data & aborting (open, close, while, split
& die)
#!/usr/local/bin/perl
&buildPasswordList(
'secret_password.file' ); # Self-contained tasks should
generally be put into their own subroutines
print "Hello,
PerlMongers!\n";
print "And what's
your name? ";
$name = <STDIN>;
chomp $name;
if ( $name eq
'Bill' )
{ print "Cool
name, come on in!\n"; }
elsif ( $name
eq '' )
{ print "Fine,
don't tell me...\n"; exit; }
else
{
if ( &passwordOK(
$name ) )
{ print "Darth
Vader lives...come on in!\n"; }
else
{ print "I thought
I felt the good in you, but...\n"; exit; }
}
print "Welcome
to Norad. Do you want to play a game?\n";
exit;
sub buildPasswordList
{
my $filename
= shift; # Accepts real file name to connect
to
my ($line, $name,
$password); # Define as local variables to reduce
changes of "hammering" global variables
open (FILE,"<$filename")
# Create "filehandle" to access file data; < = read-only, > = overwrite,
>> = append
or die
"Can't find password file!\n"; # Program exits with this msg if
any problems with open statement
while ($line
= <FILE>) # Loop will execute for each line
in FILE in sequence, assigning value to $line
{
chomp $line;
# Ditch that newline!
($name,
$password) = split(/\t/,$line); # Split contents of $line on every
tab char, assigning values to vars in parens
$password_list{
$name } = $password; # Build name/value pair in %password_list;
DON'T MAKE THIS A LOCAL VAR!
}
close FILE;
# Close the filehandle; done anyway at program end, but good programming
style
return;
# Return is optional; this one returns nothing
}
sub passwordOK
{
my $name = shift;
print "What's
your password, $name? ";
my $userpass
= <STDIN>;
chomp $userpass;
if ( $userpass
ne '' &&
$userpass
eq $password_list{ $name } )
{ return 1; }
else
{ return 0; }
}
Writing external files,
accepting command-line arguments, negation & using shell commands (print
FILE, @ARGV, !, system)
#!/usr/local/bin/perl
$name = $ARGV[0];
# Assign first argument (zero-indexed) in list to $name
$password = $ARGV[1];
# Assign second argument in list to $password
($name, $password)
= @ARGV; # Alternate way of doing the above
$filename = 'secret_password.file';
$temp_filename
= $filename . ".tmp"; # Temp file to hold data during
processing
# Make sure
values are populated
while ( length(
$name ) < 1 ) # Loop will execute until $name
contains a value; won't execute if already populated
{
print "Enter
username: ";
$name = <STDIN>;
}
while ( length(
$password ) < 1 )
{
print "Enter
password: ";
$password = <STDIN>;
}
chomp ($name);
# Remember those newlines!
chomp ($password);
#
open(TMP,">$temp_filename");
# Selecting overwrite ensures data from previous runs is properly deleted
open(FILE,"$filename");
# If no control prefix (>,>>,<,etc.), open defaults to read-only
while ($line =
<FILE>) # Iterate through the file
line-by-line
{
# NOTE: this
should be done with regular expressions
#
my($file_username,
$file_password) = split(/\t/,$line); # Break out values
if ( $file_username
eq $name )
{
# Found
old entry; overwrite it
print TMP
"$name $password\n"; # Insert filehandle name after print to direct
output to it
$found_old_entry
= 1; # Set flag indicating that name/password has
been written to the file
}
else
{
# This
is not the entry; don't overwrite
print TMP
$line; # Print current line to TMP unchanged
}
}
if ( !$found_old_entry
) # A ! before a variable or conditional
is a "negation" operator (yes returns no, etc.)
{
# No previous
entry was found for this user; write it fresh
print TMP "$name
$password\n";
}
close FILE;
# Close filehandles
close TMP;
#
# Move TMP onto
original file to complete edit process
system("mv $temp_filename
$filename"); # 'system' generates a new shell &
executes supplied command, discarding output
exit;
Recommended beginner
reading:
1) Learning Perl, Randal
L. Schwartz (O'Reilly)
- the classic
"starter" book, now in its 2nd edition
2) Perl Cookbook, Tom
Christianson & Nat Torkington (O'Reilly)
- hundreds of
well-commented solutions to common problems, organized by subject: strings
to OOP to web automation
Return to the Grand Rapids Perlmongers homepage.