Thursday, October 4, 2007

Newbie: Learn Perl in 10 easy lessons(Part I)

Learning Perl: Lesson 1

Thanks to the Perl scripting language you can automate various tasks in your Linux system. Learning Perl is both easy and fun, and you'll soon be able to write scripts which will make your life easier. In these series of articles I'll start by explaining the basics and I'll progressively introduce more complex concepts and advanced techniques. I'll try to explain things as much as possible, so whether you are familiar to programming or not, you should find it easy to learn Perl and be comfortable with using this language after the end of this series of articles.

History of Perl

Larry Wall created a scripting language in 1987, which he called the "Practical Extraction and Report Language". It was designed as a text-processing language for Unix operating systems. Various tools and languages already existed (Unix shells, sed, awk, C...etc) and programmers usually used many of them together. Larry Wall wanted the language to cover all aspects and needs related to text-processing so the programmer wouldn't have to use any other tool in conjunction with Perl. Also, he designed Perl as a language that was easy and fast to use but which would also allow the programmer to get into the innards of things.

Perl offered features no other language had offered before. It was filling a niche no other tool had, and it immediately became popular. In 1994, Perl 5 was released and at that stage it was a stable and well established general purpose programming language.

Particularities of Perl

Perl is truly unique. As we go along and study its different features you'll probably see that by yourself. Larry Wall applied a lot of his linguistic knowledge into the making of Perl. Some people even consider it a natural language. Its vocabulary is extremely rich and its grammar is very flexible. Perl programmers usually say "There's more than one way to do it". In fact, you can literally write a Perl script your way, with your own style. Some people even do "poetry" in Perl :) Because of this, some Perl scripts can be very difficult to read. Writing them though, is always a pleasure.

The Perl interpreter

Perl is an interpreted language. This means that the code you will write using the Perl language will need a program called the Perl interpreter in order to be run. For instance, if you write a Perl script in a file called myScript.pl (.pl is commonly used as an extension for Perl scripts), you will not be able to run it directly. You will need to call the interpreter to run it:

perl myScript.pl

In this example

myScript.pl
is your
Perl
script and perl is the Perl interpreter.

Installation of the Perl interpreter

The Perl interpreter is an essential tool and it is usuallyinstalled by default on most GNU/Linux distributions. Forinstance, the following distributions come with a recent and updatedversion of Perl:

  • Suse 10.1
  • Fedora Core 5
  • Debian Testing
  • Ubuntu 5.10
  • Mandriva 2006
  • Slackware 10.2
  • Mepis 3.4-3
  • Gentoo 2006.0
  • Knoppix 5.0

For an exhaustive list of distributions which include perl, you can search distrowatch.com: http://distrowatch.com/search.php?pkg=perl&pkgver=5.8.8#pkgsearch

To makesure the interpreter is installed on your machine and to see which version it is, you can open a terminal and type:

perl -v

If it is installed, this should print the version of Perl installed on your machine:

rakesh@debian:~> perl -vThis is perl, v5.8.8 built for i586-linux-thread-multiCopyright 1987-2006, Larry WallPerl may be copied only under the terms of either the Artistic License or theGNU General Public License, which may be found in the Perl 5 source kit.Complete documentation for Perl, including FAQ lists, should be found onthis system using "man perl" or "perldoc perl".  If you have access to theInternet, point your browser at http://www.perl.org/, the Perl Home Page.

If Perl is not installed on your system, you will certainly be able to install it through your distribution's package manager. Simply search for perl within your distribution's repositories, or start considering using another distribution. After all, Perl is an essential tool which should be included by default and regularly updated by your distribution: http://www.cpan.org/ports/#linux

Implicit use of the interpreter

The Perl interpreter is usually used to run Perl scripts which are written in a file. It also features an interactive mode which you can use by simply typing perl without any argument. However, in this lesson we will focus on using files.

In order to run a Perl script, you can call the interpreter with the file as an argument:

perl myScript.pl

... or you can tell the Perl script where to find the interpreter and make the script executable. This is common practice among programmers and you are encouraged to do so. Within the script file, the first line tells the shell how to interpret the file. This line basically shows the path to the Perl interpreter:

#!/usr/bin/perl

Note: The Perl interpreter is usually installed in /usr/bin, but your system might be different. To make sure, type "which perl":

rakeshdebian:~> which perl/usr/bin/perl

Also make sure your Perl scripts are executable and have proper permissions:

chmod a+rx myScript.pl

Once the script is executable, it can be run directly. The shell looks at the first line of the file which starts with “#!”, and then it runs the interpreter which path is found on that line with the rest of the file. In other words, thanks to that little trick, you can run you Perl script directly:

./myScript.pl

Although you are not explicitly calling the interpreter here, keep in mind that it is actually run by the shell on your behalf and that it is the interpreter which runs your script.

Your very first Perl script!

You have your interpreter installed, and you're ready for your first script: a simple script that writes "Hello World!" on the screen (I know.. it's a bit useless, but it's more or less a tradition when you're learning a new programming language, so let's simply write "Hello World" and enjoy the lesson since it's still easy to understand :)).

Create a file called helloWorld.pl and write the following into it:

#!/usr/bin/perlprint "Hello World! \n";

Make the script executable:

chmod a+rx helloWorld.pl

Run the script:

./helloWorld.pl

As you probably expected, "Hello World!" gets printed on the screen. The script only contains two lines and is quite easy to understand. The first line will always be the same; it tells your shell where to find the Perl interpreter. The second line is actually the only Perl instruction of your script, it tells the interpreter to print "Hello World!" on the screen. In Perl, each instruction finishes with a semicolon. If you're new to programming you'll probably forget semicolons in your code, so be careful with that. The reason for the semicolon is that an instruction can sometimes be long and take more than one line, so it is an effective way to mark the end of an instruction. Most languages use semicolons and once you're used to it, it seems very natural. You might also wonder what the "\n" is for. It simply is a special character which corresponds to the new line character (as when someone presses the Enter key) so that the cursor goes the next line of the screen after printing "Hello World!".

In the next lesson we'll start using variables, opening files and do a lot of things which will come handy for you later. Now that you know what Perl is and how to use it, we'll start to focus on the language itself. Of course, in the meantime I'll be glad to answer your questions.


Learning Perl: Lesson 2

What are variables?

Variables are used in every computer language. If you are new to programming, remember the variables used in algebra equations. For instance, consider the following equation:

a + 5 = 7

In this equation, there is only one variable. Its name is "a" and its value is "2". Variables always have a name and they always have a value. In algebra their value is usually a number. In programming, their value can be a number, a character, a string (which means a sequence of characters), or even a complex object such as an array, a hashtable, a data structure, etc... Throughout the lessons we will use variables to store many different types of objects or values and you will become more familiar with the different data types that a variable can represent.

Variables in Perl

In Perl, there a three types of variables: * scalar variables, * arrays, * hashtables.

Scalar variables store a single value. In Perl, scalar variables names are always prefixed with a dollar sign. For instance:

$a = 2;
$message = "Hello World!";

Arrays can store many values. In Perl, arrays are always prefixed with an at-sign. For instance:

@colors = ("red", "green", "blue");@primaryNumbers = (1, 2, 3, 5, 7);

Hashtables are a special kind of array: associative arrays. They are like arrays, but for each of the value they store, they also store a corresponding name or label. They consist of pairs of elements - a key and a data value. In Perl, hashtables are always prefixed with a percent sign. For instance:

%phoneNumbers = (Alicia =>  "090-64-773315",             Tom => "085-153-3214",             Jimmy => "085-285-4545");

In this lesson we will focus on scalar variables and arrays. They are simple to use and they will help us write our calculator.

What are command line arguments?

In the previous lesson we first called our script by invoking the Perl interpreter:

perl myScript.pl

Then we saw how to make an implicit call to the interpreter so that the script could be called directly:

./myScript.pl

Whether we call the interpreter implicitly or explicitly, we can give arguments to the script. These arguments are given while calling the script, and simply put after the script name:

./myScript.pl argument1 argument2 argument3

For instance, instead of having a script which writes "Hello World!" on the screen, and thus doesn't need any argument, we will write a calculator in this lesson. Our calculator will calculate the result of a simple equation which we will give as a command line argument. For instance, if we wanted our calculator to add 5 and 6, we would call it like this:

./calculator.pl 5 + 6

In this example, we gave three command line arguments:

  • 5
  • +
  • 6

The Perl script will have to look at these arguments, identify the second argument to know what operation to do with the first and third arguments, calculate and print the result on the screen. Command line arguments in PerlWhen the interpreter runs the Perl script it stores the command line arguments in an array called @ARGV. Note that the Perl language is case-sensitive, so it is important to use capital letters here. @ARGV is an array, and like every array in Perl you can do the following on it:

  • Get the first element of the array by typing $ARGV[0] (note that as this is a single value it is represented by a scalar variable and prefixed with a dollar sign).
  • Get the second elements of the array by typing $ARGV[1]... etc.
  • Get the index of the last element in the array by typing $#ARGV.

Note that arrays always start from 0, not from 1. Therefore the first element of an array, is element 0, not element 1. For instance element number 12 corresponds to the 13th element of an array. This is a convention in many programming languages. The index of the last element in the array corresponds to the number of elements - 1.

In our example, we call our calculator by giving it three arguments:

./calculator.pl 5 + 6

Therefore we can expect the @ARGV array to contain three elements, $#ARGV being equal to 2 and $ARGV[0], $ARGV[1] and $ARGV[2] respectively being equal to 5, "+" and 6.

Your second Perl script, the Calculator!

You nearly know everything you need in order to code your second Perl script and to write a nice calculator. In fact you could do it yourself now! As we said before, there are more than one way to do something in Perl. Try to program the calculator by yourself, and then have a look at the solution below.

Create a file called calculator.pl and write the following into it:

#!/usr/bin/perl$nbArguments = $#ARGV + 1;print "number of arguments: $nbArguments\n";exit(1) unless $nbArguments == 3;$a = $ARGV[0];$b = $ARGV[2];$operation = $ARGV[1];if ($operation eq "+") {        $result = $a + $b;}elsif ($operation eq "-") {        $result = $a - $b;}elsif ($operation eq "/") {        $result = $a / $b;}elsif ($operation eq "x") {        $result = $a * $b;}print "$a $operation $b = $result\n";

Make the script executable:

chmod a+rx calculator.pl

Run the script :

./calculator.pl 5 + 6./calculator.pl 11 - 2./calculator.pl 4 x 3./calculator.pl 33 / 3

The script works as expected, but there probably are a lot of instructions you didn't fully understand within this script. So let's look at them.

The first line tells where to find the interpreter, so that we can call the script directly.

The second line takes the index of the last element from the @ARGV array and adds 1 to it. That way it gets the number of command line arguments given to the script and stores it in a variable called $nbArguments.

The third instruction simply prints the number of arguments on the screen.

There is a lot to say about the fourth instruction (exit(1) unless $nbArguments == 3;):

  • "exit" is a Perl function which makes the script stop and return a given code to the shell. In this example the script stops and returns 1 to the shell. 1 is a Unix convention which means that there was an error.
  • "unless" is the opposite of "if". These are Perl statements. In this example, "exit" is called unless the following statement is true "$nbArguments == 3".
  • In Perl, and in many programming languages, the equal sign is used to affect values to variables. For instance, when we wrote $nbArguments = $#ARGV + 1, we assigned a value to $nbArguments. The double equal sign "==" is a comparison operator which returns true or false depending on the fact that the variables or values on both side are equal or not. Perl also provides another operator "eq" which compares strings. Try to use "eq" for string comparisons and "==" for numbers. Remember that the "=" sign assigns values and is not a comparison operator.
  • In brief, (exit(1) unless $nbArguments == 3;) means that the script will stop unless three command line arguments were given.

The three next instructions simply assign the three command line arguments to variables. We stored the first one in $a, the third one in $b and the second on in $operation.

Then, depending on the value of $operation, we made a different calculation with $a and $b and stored the result in a variable called $result. Note that we used "if" and "elsif" statements. We will come back to these statements later, but for the moment remember that "elsif" is a contraction for "else if...". Also, note that we used brackets to clearly identify blocks of code between the if statements and that we indented our code. In general, unless you have a very simple one liner to write, use brackets for each if statement and always indent your scripts.

The last instruction writes a summary of the operation and its operands as well as the result on the screen.

In this lesson we learnt how to use variables and command line arguments. We also had a quick look at If statements, comparisons operator and a few operations. In the next lesson, we'll manipulate text files and go a bit further in using operators and other statements.


Learning Perl: Lesson 3

What are If statements and loops?

Every Perl script is made of instructions which tell theinterpreter what to do. Depending on the purpose of the script you'llwrite different instructions. Sometimes, you might want someinstructions to be executed only on certain conditions. To do this,you'll use If statements. A typical If statement is aninstruction which defines three elements:

  • A condition

  • A set of instruction to execute if the condition is met

  • A set of instruction to execute if the condition is not met

For instance,consider the following code:

if ($time > 12){
print "Good Afternoon";
}
else {
print"Good Morning";
}


In this Ifstatement, the condition is ($time > 12). If the condition is metthen the script prints "Good afternoon", otherwise itprints "Good morning".

Sometimes, you might wantsome instructions to be executed more than once. For this you can useloops. A typical loop is composed of a condition and a set ofinstructions to execute. There are different kinds of loops and wewill study them in the chapters below.

If statements in Perl

Perl is a very flexible language and this is particularly truewhen it comes to If statements.

Simple If-statements

The most common form of If statement in programming is composed ofa condition (between parenthesis) followed by a set of instructionswhich are placed between brackets. For instance:

if ($time > 12) {
print "time is $time\n";
print"Good Afternoon\n";
}


Although it is considered bad practice, you don't have towrite the brackets if there is only one instruction in the Ifstatement:

if ($time > 12)
print "Good Afternoon\n";

To avoid any possible confusion, it is recommended to always writethe brackets, or, if there is only one simple instruction to placethe condition and the instruction on the same line:

if($time > 12) print "Good Afternoon\n";

In Perl, you can also write the condition after the instructionitself. For instance:

print "Good Afternoon\n" if($time > 12);

Else and Elsif Statements

Similarly, you can define an “else” block of instructions,which will be executed if the condition is not met:

print"time is $time\n";
if ($time > 12) {
print "GoodAfternoon\n";
}
else {
print "Good Morning\n";
}

Sometime you may want to dosomething depending on more than one condition. Of course you canalways define If statement within others, but you can also use elsif,as a contraction of “else, if (something else..)”:

if ($time <>

Unless-statements

In Perl, you can use the Unlessstatement. It behaves exactly like the If statement but executes thecode if the condition is not met. For instance the following codeprints “Good night” if it's more than 11pm:

print "Good night\n" unless($time <>

Loops in Perl

There are many different kinds of loop in Perl. Here are the mostcommon types.

While loop

This loop executes a block of code while a condition remains true.For instance, the following code prints “Hello” three times:

$i = 0;
while ($i < i =" $i">

Until loop

This loop executes a block of code until a condition becomes true.For instance, the following code prints “Hello” three times:

$i = 1;
until ($i > 3) {
print "Hello\n";
$i = $i + 1;
}

For loop

The for loop is composed of four elements:

  • A starting assignment

  • A condition

  • An incrementation

  • A set of instructions

The notation of the For-loop is as follows:

for (starting assignment; condition; incrementation) {
instructions
}

The for loop starts by executing the starting assignment. Then,while the condition is met, it keeps executing the instructions andthe incrementation. For instance the following For-loop prints“Hello” three times:

for ($i = 0; $i < i =" $i">

Note that the ++ operator is usually used to increment a variable,so we could have written $i++ instead of $i = $i + 1;

In Perl, you can also use the For-loop with a “range operator”.The notation for the range operator is “..”. For instance, thefollowing code prints “Hello” three times:

for (1..3) {
print "Hello\n";
}

Foreach loop

The foreach loop is used to iterate through the elements of anarray. For instance, the following code prints the days of the week:

@days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
foreach $dayOfTheWeek (@days) {
print "$dayOfTheWeek\n";
}

You can also use the foreach loop to iterate through the keys of anhashtable. For instance, the following code prints the days of theweek:

%days = ();
$days{"Monday"} = 1;
$days{"Tuesday"} = 2;
$days{"Wednesday"} = 3;
$days{"Thursday"} = 4;
$days{"Friday"} = 5;
$days{"Saturday"} = 6;
$days{"Sunday"} = 7;

foreach $day (keys %days) {
print "$day is the day number $days{$day} of the week\n";
}

File Handling

The Perl language was designed to make file handling easy andefficient, so you'll probably won't have any problem opening filesand reading them.

Opening and closing files

In order to open a file, you'll use the “open” instructionwhich takes two arguments: the name of a filehandle and the name ofthe file itself. The filehandle is like a variable which representsthe handling of the file within the script. For instance, in thefollowing code we're opening the file “clients.txt” with afilehandle called CLIENTS:

open (CLIENTS, "clients.txt");

By default, the file is open in read-mode, which means you canonly read from it. You can decide to open a file in write-mode, inorder to be able to write into it. If the file already existed or hadsome data written into it, the data will be lost. To open a file inwrite-mode simply add a “>” in front of the file name:

open (CLIENTS, ">clients.txt");

If you'd rather keep the data written in the file, you can openthe file in append-mode. This way, the data will be kept, and whatyou'll write in the file will be appended to it. In order to do thisadd a “>>” in front of the file name:

open (CLIENTS, ">>clients.txt");

The “open” instruction returns true if it managed to open thefile, false otherwise. You can use this value in order to test thesuccess of the operation. For instance, the following code opens thefile in write-mode and prints “Insufficient privileges” if thescript doesn't manage to do so.

open (CLIENTS, ">clients.txt") or print "Insufficientprivileges\n";

Remember to always close the files once you're finished with them.If you don't your changes might be lost. In order to close a file,simply use the “close” instruction on the filehandle:

close (CLIENTS);

Writing into files

Once the file is open in write mode you can write into it simplyby writing into its filehandle. The “print” instruction writesthings on the screen by default, but you can specify a filehandle towrite into. For instance, the following code adds a line “Mr JohnDoe” in the end of the “clients.txt” file:

open (CLIENTS, ">>clients.txt") or die "Insufficientprivileges\n";
print CLIENTS "Mr John Doe\n";
close (CLIENTS);

Reading data from files

There are many ways to read the content of a file. Here are thetwo most common ways in Perl.

Copying the content of the file into an array

You can copy the whole content of the file into an array. Eachline will then correspond to an element of the array. Here is anexample:

open(CLIENTS, "clients.txt");
@lines = ;
close(CLIENTS);
print @lines;

Looping through the filehandle

Alternatively you can loop through the filehandle in a while loopby writing while($line = ) (think of it as “whilethere are lines in the clients file, I'm assigning the current lineto $line):

open (CLIENTS, "clients.txt");
while ($line = ) {
print $line;
}
close (CLIENTS);

As you can see, Perl makes it very easy to manipulate files. Inthe next lesson we'll look at how to search for a particular elementwithin a file, and how to handle and manipulate strings.


Learning Perl: Lesson 4

String comparisons

The =~ operator

Perl provides an operator which you'll find very useful to parseand search files: "=~". If you are not familiar with thisoperator, think of it as a "contains" operator. Forinstance:

"helloworld" =~ "world" returns true, as "helloworld" contains "world".
"helloworld" =~ "o worl" also returns true since "oworl" is included in the string "hello world".
"helloworld" =~ "wrld" returns false because thestring "hello world" does not contain "wrld".

Using the =~ operator you can easily testif a variable contains a particular string, and this will help you alot while parsing text files. You can also use regular expressions inconjonction with the =~ operator. Although it is too early at thisstage to study regular expressions in details, here are sometechniques that you can use with =~.

We replace the doublequotes by forward slashes in order to tell our =~ operator that we'renot simply looking for a string anymore but for a matching pattern(with a bit of logic inside it):

"helloworld" =~ "world" is the same as "helloworld" =~ /world/

Although"world" represents a string and /world/ represents anexpression, these two instructions return true. By adding logic tothe expression, we can refine the meaning of our =~ operator.

=~/^Starts with/

A leading ^ sign changes the meaning of the operator from"contains" to "starts with":

"helloworld" =~ /world/ returns true because "hello world"contains "world".
"helloworld" =~ /^world/ returns false since "hello world"doesn't start with "world".
"helloworld" =~ /^hell/returns true because "hello world" starts with"hell".

=~ /Ends with$/

By adding a $ sign in the end of the expression you can change themeaning of the operator from "contains" to "endswith":

"hello world"=~ /world/ returns true because "hello world"contains "world".
"helloworld" =~ /world$/ also returns true, but this time it'sbecause "hello world" ends with "world".
"helloworld" =~ /hello$/ returns false, because "helloworld" doesn't end with "hello".

The eq and ne operators

You can use both the ^ and $ signsin the same expression, and it would mean that you're looking for astring with which your variable would both starts and end. Forinstance:

"hello world"=~ /^hello world$/ returns true because "hello world"starts and ends with "hello world".
"helloworld" =~ /^hello$/ returns false, because although"hello world" starts with "hello" it doesn't endwith it..

Note that there is no much point using both ^ and $in the same expression. If you're string starts and ends withsomething it is likely to be equal to that something... if you wantto test the equality of two strings, you can simply use the eqoperator:

"hello world"eq "hello world" returns true because the twostrings are identical.

The ne operator tests the non-equalityof two strings. It returns true if the strings are different andfalse otherwise:

"helloworld" ne "good night" returns true.

"helloworld" ne "Hello worlD" returns true (remember that Perlis case-sensitive)

"helloworld" ne "hello world" returns false because bothstrings are the same.

Remember to use the eq and ne operatorsto test the equality of strings in Perl, and their equivalence == and!= to test numerical values.

The !~ operator

The !~ operator is used as a “does not contain” operator. What!= is to ==, ne is to eq and !~ is to =~. For instance:

"hello world" !~ "world"returns false because “hello world” does contain “world”.

"hello world" !~ "wwt"returns true because “hello world” does not contain “wwt”.

Case insensitive search

When you use the =~ operator you test the matching of a stringwithin another, this is always case sensitive. For instance:

"hello world" =~ "world"returns true.

"hello world" =~ "woRld"returns false.

If you want to make the =~ operator insensitive, add an “i”after the expression:

"hello world" =~ /world/ireturns true.

"hello world" =~ /woRld/ialso returns true.

Substitutions

The =~ operator can also be used to find occurrences of a stringwithin a variable and substitute them with another string. Forinstance, if you have a variable which contains text, and you want tochange all occurrences of “aaa” with “aab” within that text,you can simply use the following substitution:

$variable =~ s/aaa/aab/;

All occurrences of “aaa” within $variable will then be changedto “aab”. Note that we prefixed our expression with an “s” tochange the meaning of the operator from “contains” to“substitute”.

Parsing files

There are many ways to parse a text file. In Perl, if the file hasits data organized line by line with delimiters, it is very easy toparse it.

Let's study a simple example. We have a set of employees in a filecalled employees.txt. In this file, each line represents an employee.The information relative to each employee is delimited with tabs, thefirst column is the name of the employee, the second column indicateshis department and the third one his salary. Here is an overview ofthe file:

Mr John Doe R&D 21000
Miss Gloria Dunne HR 23000
Mr Jack Stevens HR 45000
Mrs Julie Fay R&D 30000
Mr Patrick Reed R&D 33000

In order to obtain some statistics, the HR department wants toestablish a list of all male employees who work in the R&Ddepartment and which salary is more than 25000.

To obtain this list, we design a simple Perl script, which:

  1. opens the employees.txt file

  2. loops through each line

  3. identifies the name, department and salary of the employee

  4. ignores and goes to the next line if the employee is female (the name does not start with Mr)

  5. ignores and goes to the next line if the salary is less or equal to 25000.

  6. ignores and goes to the next line if the department is not “R&D”.

  7. prints the name and the salary of the employee on the screen.

To do this, we'll introduce two Perl functions:

  • “chomp” is used to remove the carriage return found in the end of the line. For instance chomp $variable removes all carriage returns in the variable.

  • “split” is used to cut the line in different parts where it finds a delimiter. For instance split /o/, “hello world” returns an array containing “hell”, “ w” and “rld”. In our example we'll split the lines with the tab delimiter, which in Perl is written “\t”.

Here is the script which establishes the list of male employeesfrom the R&D department with a salary greater than 25000. To makethings a bit clearer, comments were introduced within the scripts(comments in Perl start with a # sign):

#open the employeesfile
open (EMPLOYEES,"employees.txt");

#for each line
while ($line =) {

#remove thecarriage return
chomp $line;

#split the linebetween tabs
#and get thedifferent elements
($name,$department, $salary) = split /\t/, $line;

#go to the nextline unless the name starts with "Mr "
next unless$name =~ /^Mr /;

#go to the nextline unless the salary is more than 25000.
next unless$salary > 25000;

#go to the nextline unless the department is R&D.
next unless$department eq "R&D";

#since allemployees here are male,
#remove theparticle in front of their name
$name =~ s/Mr//;

print"$name\n";
}
close (EMPLOYEES);

Study the script carefully and makesure you understand every part of it. Each instruction was eitherexplained in this lesson or in one of the previous ones. If you haveany question, do not hesitate to ask.

In the next lesson we'll look at how tointeract with the filesystem and the Linux operating system from ourPerl scripts.


Learning Perl: Lesson 5

Executing system commands

Perl provides a function called “system” which canexecute a command or a set of commands directly on the operatingsystem. In fact, Perl passes the command to the operating system, whichexecutes it, and then returns the result back to Perl.

So, for instance, the following Perl script prints the content of the current directory:

#!/usr/bin/perl

system("ls");

What actually happens is that the Unix process which runs the Perlinterpreter forks and the newly created child Unix process executes the“ls” command. When the execution finishes, it returns theexit code of the command back to the Perl interpreter.

If you are familiar with Unix commands exit codes you can test thesuccess of the execution of your command by assigning the return valueof “system” to a variable, and then evaluate this variable.For instance:

$lsExecutedSuccessfully = system(“ls”);

Here, if “ls” executes successfully, the variable$lsExecutedSuccessfully receives the value 0. This value corresponds tothe successful exit code of the command “ls”.

Executing system commands and capturing the output

Sometimes, when you run a Linux command from your Perl script you'remore interested in what it writes on the screen than in its exit code.For instance, when you execute “ls” you're more likely tobe interested in the list of files being printed on the screen than inthe value 0 returned by “system”.

To achieve this, you can use evaluated quotes “`”instead of “system”. Not only does it executes the command,but it also returns what the commands writes in its standard output:

@files = `ls`;

In this example, the listing of the files returned by“ls” does not appear on the screen. Instead, it gets storedin the @files array.

Changing the working directory

In the shell you would type "cd /home" to change the workingdirectory to /home. You could write the following in your Perl script:

system("cd /home");

But it would have no effect. In fact, since the system call forksfrom the process used by the interpreter, it doesn't change the workingdirectory of your script. Instead, you can use a Perl function called"chdir":

chdir "/home";

Interacting with the filesystem

Perl provides a lot of functions to interact with the files anddirectories of your filesystem. Here are some of these handy functions:

chmod

"chmod" changes the permissions of a file or a list of files andreturns the number of files that were changed. The first argument mustbe the numerical mode. Examples:

chmod 0777, "/home/clem/program.pl";

chmod 0777, @myFiles;

symlink

"symlink" creates a symbolic link. It is the equivalent of "ln -s".The first argument is the file name, the second argument is the linkname. Example:

symlink "/home/clem/program.pl", "/usr/bin/program";

mkdir

"mkdir" creates a directory. The first argument is the name of thedirectory and the second argument is the octal mode which defines thepermissions for that directory. For example:

mkdir "/home/clem/perl_programs", 0664;

rename

"rename" is the equivalent of "mv" in Unix. It renames or moves a file. Example:

rename "/home/clem/program.pl", "/home/clem/program";

rmdir

"rmdir" deletes a directory, but only if it is empty. Example:

rmdir "/home/clem/perl_programs";

stat

"stat" returns a 13-element array which represent the properties of a file. The elements of the array are :

0: $dev, 1: $ino, 2: $mode, 3: $nlink, 4: $uid, 5: $gid, 6: $rdev,7: $size, 8: $atime, 9: $mtime, 10: $ctime, 11: $blksize, 12: $blocks

Example:

stat "/home/clem/program.pl";

unlink

"unlink" deletes a file or a list of files. Example:

unlink "/home/clem/program.pl";

Perl Script Exercise: Netswitch

In this exercise, we want to be able to switch between networks. Wedefined network configuration files in a directory called "networks".

For instance, here is the content of ./networks/home:

interface=eth2

type=dhcp

proxy=none

And here is the content of ./networks/work:

interface=eth1

type=dhcp

proxy=www-proxy.work.com

proxy_port=8080

The following Perl script takes a network name as its command lineargument, opens the file with the same name from ./networks and setsthe network interface with the data taken from the content of that file:

#!/usr/bin/perl

#default values

$interface="none";

$type="none";

$address="none";

$gateway="none";

$dns="none";

$proxy="none";

$proxy_port = "none";

#gather information from the network file

$network = $1;

$networkFile = "./networks/$network";

open (NETWORK, "$networkFile") or die "$networkFile not found or not readable\n";

while ($line = ) {

chomp $line;

($variable, $value) = split /=/, $line;

if ($variable eq "interface") $interface = $value;

elsif ($variable eq "type") $type = $value;

elsif ($variable eq "address") $address = $value;

elsif ($variable eq "gateway") $gateway = $value;

elsif ($variable eq "dns") $dns = $value;

elsif ($variable eq "proxy") $proxy = $value;

elsif ($variable eq "proxy_port") $proxy_port = $value;

}

#make sure the type and interface are defined

if ($interface eq "none") die "Interface name not defined\n";

if ($type eq "none") die "Network type (dhcp, static) not define\n";

if ($type eq "dhcp") {

print "Network type: dhcp\n";

#just get an IP address and settings from the DHCP Server

system("dhclient");

}

elsif ($type eq "static") {

print "Network type: static\n";

#bring the interface up

if ($address eq "none") die ("IP address not defined\n");

system("ifconfig $interface $address up");

if ($gateway ne "none") {

print "Gateway: $gateway\n";

system("route add default gw $gateway");

}

if ($dns ne "none") {

print "DNS Server: $dns\n";

$strNameServer = "cat "."'"."nameserver $dns"."' > /etc/resolv.conf";

system($strNameServer);

}

}

else die "Bad network type : $type. Use dhcp or static.\n";

Try to understand each line of that script. The script doesn't setthe proxy in APT, Firefox...etc. See if you can update the script toadd such functionality. Also, it would be great if the script couldlist the possible networks available when the user types "netswitch-l". As there are many ways to solve a problem, especially in Perl,please post your solutions and ideas. Together you should be able towrite a great network switcher.

You now know all you need to start writing this script, however if you have any questions do not hesitate to ask.

Contd...(Part II)

No comments: