Note: This is the part that we could not get to on Thursday, Sept 3, 1998. It will be covered in Lecture No. 3, on Tuesday, Sept 8, 1998, which will be our first step towards CGI programming. What follows is therefore a quick introduction to Perl, or what we need in order to get started with CGI in Perl.

A Quick Perl Primer

Let's first write a Perl program and see it run.

Use pico, emacs or another editor and create a file called one with the following contents:


print "Hello, world!";
This is a complete Perl program, but can you run it already?

Look at the file with the ls command: ls -l one
-rw-r--r--   1 dgerman  students      41 Sep  4 15:16 one 
(Ask me about my umask value.)

The -rw-r--r-- means that this file can be read and modified by the owner (dgerman) and can be viewed by the groups to which the owner belongs to and by the world. To make this file executable use chmod: chmod +x one ls -l one
-rwxr-xr-x   1 dgerman  students      41 Sep  4 15:16 one 
The file is now executable and we can run it: ./one
Hello, world!
Change the program as indicated below:

print "Hello, world!\n"; 
And run it again ./one
Hello, world!
and now we are ready to start our Perl tutorial.

The first line in any Perl script must start with a hash sign (#) followed by an exclamation sign (!) and then by the absolute address of the perl interpreter (which is located in /usr/local/bin/perl on burrow and on most other Unix systems).

The perl interpreter is, like your web server, just another program. ls -l /usr/local/bin/perl
-rwxr-xr-x   3 root     daemon    794248 Feb 27  1998 /usr/local/bin/perl file /usr/local/bin/perl
/usr/local/bin/perl:    ELF 32-bit MSB executable SPARC Version 1, dynamically linked, not stripped 
When a Perl script gets invoked the perl interpreter is located and started (using the first line of the script). The interpreter then takes care of the rest of the file which is, in fact, the Perl program.

We will now provide an introduction to Perl through a set of examples.

1. The empty program is a valid program. vi empty cat empty
#!/usr/local/bin/perl chmod +x empty ./empty 
2. Scalar variables are identified by a special prefix, the dollar sign. If we wanted to write a program that computes the value of 3 + 5 and stores that in x it could look like this: vi two cat two

$x = 3 + 5; chmod +x two ./two 
Of course this program does not communicate much. To print the value of x we use the print command. vi two cat two

$x = 3 + 5; 
print $x; ./two
print takes a list of arguments, separated by commas, evaluates them, and prints the results to the screen. $x evaluates to an integer, gets printed, and then the program terminates. Control returns to the operating system which prompts the user for more input.

Other things that we could print are characters and strings. Let's look at strings first. We could start by saying that strings are sequences of characters that appear in between double quotes. Thus

is a string, and so is
"two words"
 "      " 
the last one being a string of exactly 6 blanks.

So we can change the program that computes 3 + 5 to add a blank space after the result. vi two cat two

$x = 3 + 5; 
print $x, " "; ./two
This way the result (8) doesn't get as cluttered as before by the prompt.

In strings delimited by double quotes certain combinations of characters have a special, clearly determined meaning. For example the following group of two characters: \n stands for a carriage return (or newline). So if we change the script that computes the results of 3 + 5 and prints it out to print "\n" instead of " " after the result


$x = 3 + 5; 
print $x, "\n";
the output appears on a line of its own: ./two
3. Lists can be stored in variables that are prefixed by the symbol @. Here's a program that assigns a list of integers to a variable a. Using the foreach construct it goes over the entire list of variables and adds them up, to print the result at the end. vi three cat three

@a = (1, 2, 3, 4); 

foreach $a (@a) {
  $sum += $a; 

print "The sum is: ", $sum, "\n"; chmod +x three ./three
The sum is: 10
As they say, by the principle of least surprise the sum variable gets initialized to 0, and so it's 0 the first time it's used. The foreach loop uses a variable $a that takes every value in the list @a in turn; each such value is added to $sum, the $sum += $a being a short form of $sum = $sum + $a;

Lists have their elements in a certain order, and indexed by their position in their list. For example the first element of the list @a has index 0 and can be referred to as $a[0]. Here's program three modified again to print the value of the third element of the list, $a[2]. (Note that the first element having index 0 the third one will have index 2). vi three cat three

@a = (1, 2, 3, 4); 

print "The third element has value: ", $a[2], "\n"; ./three
The third element has value: 3
A special (perhaps intimidating) construction gives the index of the last element in list @a: $#a. This is very useful if the list changes with time (although we won't have such examples in this tutorial). Here's a modified version of three that also prints out the number of elements in the list by using the index of the last element: vi three cat three

@a = (1, 2, 3, 4); 

print "The third element has value: ", $a[2], "\n"; 

print "The list has ", $#a + 1, " elements.\n"; ./three
The third element has value: 3
The list has 4 elements.
If a list @a is empty, then $#a evaluates to -1.

4. A special list @_ is used to hold parameters passed to functions. Here's the program that uses a subroutine add to add 3 to 5 and then prints the result. vi four cat four

$x = &add(3, 5); 

print $x, "\n"; 

sub add {
  local ($a, $b) = @_; 
  return $a + $b; 
} chmod +x four ./four
The subroutine is invoked with &. The definition of the subroutine starts with sub. The two parameters of the functions are called $a and $b. They are local to the add subroutine. The subroutine simply returns the sum of its parameters. The list of parameters passed to the function can be found in @_ which is a list with a curious name: _ (underscore).

5. A simple example of recursion is fact a subroutine that computes the factorial of an integer. For an integer number n the factorial of n is written n! and is the product of all integers from 1 to n, that is 1 * 2 * ... * (n - 1) * n.

So, for example, 5! = 1 * 2 * 3 * 4 * 5 = 120.

Here's a simple Perl program that computes the factorial of 5. vi five cat five

$n = 5; $x = &fact($n); 
print "The factorial of ", $n, " written ", 
      $n, "! is equal to: ", $x, "\n";  

sub fact {
  local ($n) = @_; 
  if ($n == 0) { return 1; }
  else { return $n * &fact($n - 1); } 
} chmod +x five ./five
The factorial of 5 written 5! is equal to: 120 
The == operator is familiar to any C programmer, and so is the if statement (although in Perl the curly braces are not optional).

6. That much about passing parameters to a subroutine. Let's now talk about the way one passes parameters to the entire program. A special list is holding those values, and its name is @ARGV. $ARGV[0] is the first command line argument and the index of the last one is $#ARGV, as expected. Here's a Perl program that prints back its command-line arguments: vi six cat six

foreach $a (@ARGV) {
 print $a, "\n"; 
} chmod +x six ./six a b c
c ./six ./six 1 2 3 4 5 6
7. A simple exercise would be to modify the six program to to distinguish and signal the situation when there are no command-line parameters passed to the program at all. vi six cat six

if ($#ARGV >= 0) {
  foreach $a (@ARGV) {
    print $a, "\n"; 
} else {
  print "No arguments.\n"; 
} ./six 4 3 2
2 ./six 
No arguments.
8. Let's close our tour of Perl by introducing associative arrays. They are a very natural way of associating values with a set of distinct keys. For example we have associated host names and port numbers with usernames. No two usernames in A348/A548 are identical. Each one identifies a unique person. Each person has been assigned a host name and port number. Here are the assignments:
MABISHOP     blesmol        19800
TFBLOOMF     bobac          19800
JDUMONT      degu           19800
MFELKER      jerboa         19800
REFLYNN      marmot         19800
SPKELLOG     molerat        19800
KWLIM        prairiedog     19800
AMCCOMB      suslik         19800
DGERMAN      tucotuco       19800
JASTMILL     whistlepig     19800
TNALYWAJ     bandicoot      19801
BENDLESS     blesmol        19801
RNUSEIBE     bobac          19801
RPOPE        degu           19801
RSALERNO     jerboa         19801
EMERRILL     marmot         19801
LLTHOMPS     molerat        19801
STRAVERS     prairiedog     19801
WJWADE       suslik         19801
GRWAGNER     tucotuco       19801
JRWAGNER     whistlepig     19801
NWILLEMS     bandicoot      19802
MAKORUTH     blesmol        19802
LMANICCI     bobac          19802
BRPETERS     degu           19802
KLS          jerboa         19802
KSTANLEY     marmot         19802
DWAICUKA     molerat        19802
RITHOMAS     prairiedog     19802
JEWANG       suslik         19802
QLU          whistlepig     19802
WMA          bandicoot      19803
Here's a program that creates two associative arrays indexed by usernames, and when invoked with a username on the command line returns the assignments for the owner of that username. vi seven cat seven

%hostnames = (
MABISHOP  =>   blesmol,  
TFBLOOMF  =>   bobac,        
JDUMONT   =>   degu,        
MFELKER   =>   jerboa,       
REFLYNN   =>   marmot,       
SPKELLOG  =>   molerat,       
KWLIM     =>   prairiedog,   
AMCCOMB   =>   suslik       

%portnumbers = ( 
MABISHOP  =>   19800, 
TFBLOOMF  =>   19800, 
JDUMONT   =>   19800, 
MFELKER   =>   19800, 
REFLYNN   =>   19800, 
SPKELLOG  =>   19800, 
KWLIM     =>   19800, 
AMCCOMB   =>   19800

if ($#ARGV >= 0) {
  print $ARGV[0], 
        "'s web server runs on ", 
        " and uses port #", 
} else { 
  print "No username specified.\n"; 
} chmod +x seven ./seven JDUMONT
JDUMONT's web server runs on degu and uses port #19800 
This concludes our first tour through Perl.