Getting started with Perl, Part 1
An introduction to the language that "can do anything"
Summary
Perl can often offer a simple solution when writing a program that can be painfully difficult in shell script. In part one of this two-part series, Mo walks you through an introduction to the popular scripting language with some illustrative examples. (2,800 words)
The Perl lobby has been strong and consistent, so it is high time for me to
provide an introduction to this language.
What is Perl? In the O'Reilly & Associates book Programming Perl, by Larry
Wall (the developer of the Perl language), Tom Christiansen, and Randal L.
Schwartz, the preface describes Perl as a programming language "that makes it
easy to manipulate numbers and text, files and directories, computers and
networks."
I quote from the developer of Perl here to defend myself in advance. There are Perl fanatics out there who will tell you that anything that you can say
about what the language does is too limiting,
since it can do anything better than any other language.
Perl is indeed a very nifty programming language and is easier to use than shell programming languages. It can be used to replace any shell program, and except in very simple cases, it does a much better job (and is easier to understand) than the shell version of the same thing. It certainly fulfills its promise of easy handling of text, numbers, and files.
It's also very flexible. In fact, the motto for Perl is "There's More Than One
Way To Do It." I am well aware that in the following examples nearly every
line of code could be written in about half a dozen different ways, but this is simply meant as an introduction. If you are a Perl expert and you feel there is a better way to do
one of these tasks, you may well be right. Please be patient.
If you do not have Perl on your system, then you should install
it. It is available by starting at http://www.perl.com/, the Perl home page
on the Web.
I have chosen a simple but illustrative project to begin with, which is easy in Perl, but devilishly difficult in shell script. This project will maintain
and allow lookups in a simple text file database of names and addresses. We'll need more than one installment, so let's get started.
If you are familiar with shell programming, then you have a head start on Perl. I'll start with the traditional greeting
program. The print command
prints a string and the \n indicates a new line in the printed string. Perl
commands end with a semi-colon. You can run this Perl script by saving it as
hello and typing perl hello .
print "Yo, Adrian!\n";
A somewhat more informative version of the program adds the shebang method of
launching. If your shell supports the shebang syntax then you can identify
the program that will be used to execute the script as shown in the first
line of the following example. Save this script as hello, set its execute
mode with chmod a+x hello , and then type hello to start the program. If your
shell does not support shebang, you can still start the program by typing
perl hello .
#!/usr/bin/perl
print "Yo, Adrian!\n";
Subroutines and functions
Perl supports subroutines or functions and does not differentiate between the
two. Subroutines are very common in Perl programs. The following listing produces the same greeting by using a subroutine. Line numbers are included for
explanation.
Lines 4 through 7 define a subroutine named say_hello that
prints the message on the screen. Line 2 calls the subroutine. Perl is smart
enough to know that the program ends at line 3, after it has called
say_hello, and does not attempt to execute say_hello a second time. However,
it is always good practice to provide a clear exit in your programs, and line
3 could contain exit(0) without affecting the behavior of the program.
1 #!/usr/bin/perl
2 say_hello();
3
4 sub say_hello
5 {
6 print "Yo, Adrian!\n";
7 }
Perl variables can be created and assigned on the fly. They begin with a
dollar sign ($), much like shell variables. At line 6, the value is first
assigned to a variable, and then the variable is printed with an appended
newline. Note that the syntax of the print command allows the variable $x to
appear inside the quotes.
1 #!/usr/bin/perl
2 say_hello();
3
4 sub say_hello
5 {
6 $x="Yo, Adrian";
7 print "$x\n";
8 }
A more unique and very useful variable in Perl is the list (or array)
variable. List variables begin with the at sign (@) and are an array of
individual variables. The following listing presents two different ways of
loading a list variable, and three different ways of accessing and printing
them.
At lines 9 through 14, the individual elements of the array are
initialized. At lines 15 through 18, the array is loaded with a
comma-separated list of values. Accessing the variables is even more
flexible. Lines 20 through 26 print each individual array element with spaces
and newlines. Lines 27 through 31 assign the values in the list variable to
individual variables, by using a comma-separated list on the left-hand side
of the assignment, and then prints them. Lines 32 through 35 simply print the
whole list array as if it were a single variable. This technique
automatically inserts a space between the individual elements of the list.
You should study this example until you are comfortable with list variables. They show up a lot in Perl programs because Perl does such a
great job of handling lists and arrays of values.
1 #!/usr/bin/perl
2
3 load_hello1();
4 say_hello1();
5 load_hello2();
6 say_hello2();
7 say_hello3();
8
9 sub load_hello1
10 {
11 @msg[0]="Yo,";
12 @msg[1]="Adrian!";
13 }
14
15 sub load_hello2
16 {
17 @msg=("Yo,", "Adrian!");
18 }
19
20 sub say_hello1
21 {
22 print @msg[0];
23 print " ";
24 print @msg[1];
25 print "\n";
26 }
27 sub say_hello2
28 {
29 ($yo,$name)=@msg;
30 print "$yo $name\n";
31 }
32 sub say_hello3
33 {
34 print "@msg\n";
35 }
36
Processing files
Knowing how to process files is another basic element you will need. Perl opens files using
the open function (or subroutine). The following listing opens and prints the
contents of the /etc/passwd file on the terminal. This short listing covers a
wealth of the options available in Perl. At line 3, the open function is used
to attempt to open /etc/password and assign the open file to the file
variable TEMPFILE (file variables appear in upper case by convention in
Perl). If the open succeeds, then the statement after the "or" is ignored. If
the open fails, the statement after the "or" -- a function called die -- is executed. The die function prints a message and exits. Embedded in the
message is the special variable $!. This contains the last error message. If
/etc/password couldn't be found, the printed message would be something like
"Can't open /etc/passwd: The system cannot find the file specified."
At lines 5 through 8, a while loop reads input from TEMPFILE and prints it on
the screen. In line 5 the Perl syntax "<TEMPFILE>" is used. The angle
brackets around a file name mean "get some input from a file," in this case
one line at a time. Each line is assigned to the variable $e, and then
printed. When Perl reads in a line from a file, it includes the newline at
the end of the line, so the print $e command at line 7 does not need to
append a newline for the line to print correctly. The while test on line 5
causes the loop to continue as long as something is being read into $e from
TEMPFILE. Finally at line 10 the file is closed.
1 #!/usr/bin/perl
2
3 open (TEMPFILE, "/etc/passwd") or die ("Can't open /etc/passwd: $!\n");
4
5 while( $e=<TEMPFILE>)
6 {
7 print $e;
8 }
9
10 close TEMPFILE;
These few points cover a lot of ground, and if you are feeling lost at all,
then review from the beginning, because it only gets tougher from here.
A simple database
In order to implement a simple database, we are going to start with a simple
menu. This menu will be the front end that drives the different actions on
the address book such as adding an address or looking up an address. The menu will
be defined in a text file containing 3 fields: the letter to press to invoke
a menu action, the prompt displayed to describe the menu action, and the
command to execute when that selection is made. An example of a simple menu
file is shown below. For the moment, this file will use simple shell
commands, and as the project develops we will replace these with calls to
other Perl scripts. Colons separate the three fields, much like the field separator in a password file. The file is named menufile.txt. Line
numbers are shown, but are not included in the file. The first menu selection
will be "Say Hello Gracie" and is executed when the user types an a . The
command that is executed echoes "Hello Gracie" to the screen. The second
and third selections follow the same format. Create this file as menufile.txt
using vi or another editor.
1 a:Say Hello Gracie:echo "Hello Gracie"
2 b:Show Perl man pages:man perl
3 c:Show Current Directory:ls -l|more
We want to create a menu on the screen that looks like the
following listing and executes the commands in the third field.
a Say Hello Gracie
b Show Perl man pages
c Show Current Directory
x Exit
Enter your selection
The Perl script to create this display and behavior follows. It is long and
will take some studying. The main routine from lines 4 through 23 does its
job by calling a series of subroutines. First, at line 8 it calls
get_menu_pick(). This call will display a menu and let the user make a
selection which will end up stored in $pick. At lines 14 through 18, the main
loop executes the pick and then displays the menu again until the user enters
an x to exit from the menu. Once the loop has ended at line 21, the screen
is cleared, and finally the script exits. The get_menu_pick() subroutine at
lines 29 through 34 clears the screen, displays the menu, and gets a selection
from the user. The clear screen logic at 33 through 42 clears the screen by
printing 25 line feeds. This is an old fashioned method, but it always works.
The show_menu() logic as lines 44 through 68 includes the logic at lines 52
through 59 to open the menufile.txt and display its contents, and then close
the file.
The trick line is line 55. This line uses the split function to split
the $menurow that has just been read in. The split is the colon that appears
as /:/ in the command. This command assigns everything up to the first colon,
to $menupick, and everything from there up to the second colon, to $menuprompt.
($menupick, $menuprompt)=split /:/,$menurow;
At lines 56 and 57, these values are printed, and the number of lines is
counted. Once the printing is done, the menu file is closed. Another line is
printed containing the x/Exit option, and then some line feeds are added to
the bottom of the screen to move things up so that they are more centered.
Finally the screen ends with a request for the user's selection.
The get_pick() logic at 71 through 74 is very simple, but contains a new
feature of Perl. Note at line 73 that a line appears to be read in from a
file, STDIN, that has not been opened. In fact, Perl pre-opens several files:
STDIN for standard input, STDOUT for standard output, and STDERR for standard
error output. You can read from STDIN without having to open it. The results
of reading from STDIN are assigned to the variable $pick, and the chomp
function is used on $pick. You may remember from your earlier experience that
when you read from a file, the input includes the newline. This also applies
to input read from STDIN. The chomp() function provided by Perl is used to
cut the trailing newline off the end of a variable to clean it up, so that after chomp($pick=<STDIN>), pick contains any characters entered, but not the newline.
At lines 76 to 91, the do_pick() routine could have been written more
efficiently, but I wanted explicitly to provide another example of what
Perl does best, processing text files. In do_pick() the menufile.txt file is
read again, but this time all three fields in the record are pulled and
stored in $menupick, $menuprompt, and $menucommand. After the read,
$menucommand contains the command to be executed. The value in $menupick is
compared to the value in $pick, and if it matches, the system function is
used to execute $menucommand, and the logic breaks out of the while loop. The
last function, press_enter(), at line 94 waits for the user to input anything
and press ENTER before returning. Code this with an editor and save it as
addrmenu and you can execute it either with perl addrmenu or by giving it
execute privileges and starting it from a shell command.
1 #!/usr/bin/perl
2
3
4 #---------------------------------------
5 # MAIN ROUTINE
6 #---------------------------------------
7 # Display a menu and get a selection
8 get_menu_pick();
9
10 # as long as the E(x)it option is not chosen,
11 # execute the menu option and then display
12 # the menu again and ask for another choice
13
14 while ( $pick ne "x" )
15 {
16 do_pick();
17 get_menu_pick();
18 }
19
20 # clear the screen and exit with a 0 return code
21 clear_screen();
22
23 exit (0);
24 #---------------------------------------
25 # MAIN ROUTINE ENDS
26 #---------------------------------------
27
28 # Clear the screen, Show the menu and get user input
29 sub get_menu_pick
30 {
31 clear_screen();
32 show_menu();
33 get_pick();
34 }
35
36 # Clear the screen by printing 25 newlines
37 sub clear_screen
38 {
39 for ($i=0; $i < 25; ++$i){
40 print "\n";
41 }
42 }
43
44 # Open menufile.txt or exit with an error
45 # read in each row picking up the first two fields by
46 # splitting it on the pipe |
47 # print the first two fields
48 # send some form feeds to do some centering
49 sub show_menu
50 {
51 $count = 0;
52 open( MENUFILE, "menufile.txt") or die "Can't open menufile.txt: $!\n";
53 while ($menurow=<MENUFILE>)
54 {
55 ($menupick,$menuprompt)=split /:/,$menurow;
56 print "\t$menupick\t$menuprompt \n";
57 ++$count;
58 }
59 close MENUFILE;
60 print "\tx\tExit\n";
61 ++$count;
62 $count = (24 - $count ) / 2;
63 for ($i=0; $i < $count; ++$i){
64 print "\n";
65 }
66 print "\n\nEnter your selection\n";
67
68 }
69
70 # get user input and chop off the newline
71 sub get_pick()
72 {
73 chomp($pick = <STDIN>);
74 }
75
76 sub do_pick()
77 {
78
79 open( MENUFILE, "menufile.txt") or die "Can't open menufile.txt: $!\n";
80 while ($menurow=<MENUFILE>)
81 {
82 ($menupick, $menuprompt, $menucommand)=split /:/,$menurow;
83 if ($menupick eq $pick)
84 {
85 system $menucommand;
86 break;
87 }
88 }
89 close MENUFILE;
90 press_enter();
91 }
92
93 # put up a message and wait for user to press ENTER
94 sub press_enter
95 {
96 print "Press Enter to Continue . . .\n";
97 $dummy = <STDIN>;
98 }
99
Some things are worthy of note in addrmenu. At lines 14 and 83 there are
comparisons made against string values. One example uses "ne" and the other
uses "eq". Perl makes a distinction between numeric and string data. Even
though a variable could be named $some_number it could be assigned a totally
non-numeric value as in $some_number = "Hello". In order to make this
difference clear, Perl uses separate operators including comparison operators
for numbers and strings. Numbers use the traditional ==, !=, <, >, and <= while string comparisons use eq, ne, lt, gt, and le.
Another element to note is the calling conventions for functions. Function
arguments do not have to be enclosed in parentheses, thus the following two
lines are equivalent, but the second is more readable, looking almost like
English.
open( MENUFILE, "menufile.txt") or die ("Can't open menufile.txt: $!\n");
open MENUFILE, "menufile.txt" or die "Can't open menufile.txt: $!\n";
However, sometimes the parentheses clarify what is happening, as in the
following the example where a line is read in from STDIN and assigned to
$pick, and then chomp is used on $pick to lop off the newline at the end.
chomp($pick = <STDIN>);
In the next installment we will look at other file activities, including
writing to a file, and explore further features of Perl.
Contact
us for a free consultation. |