Pearl Script
Pearl Script
Particularities of Perl
perl myScript.pl
In this example
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
perl -v
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
Also make sure your Perl scripts are executable and have proper
permissions:
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.
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:
./helloWorld.pl
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.
LESSION 2
In the previous lesson we learnt what Perl was and how to use the interpreter to run Perl scripts. We also wrote our first Perl
script: HelloWorld.pl. In this lesson we will learn how to use variables and command line arguments. We will then use them in
order to write our second Perl script: a calculator!
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:
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:
In this lesson we will focus on scalar variables and arrays. They are simple to use and they will
help us write our calculator.
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:
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
+
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 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.
./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.
Create a file called calculator.pl and write the following into it:
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.
LESSION 3
In the previous lesson we learnt what variables were and how to use command line arguments in Perl. We also wrote our
second Perl script: the Calculator. In this lesson we will learn how to use If statements and loops and how to open files to read
and write into them.
A condition
A set of instruction to execute if the condition is met
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:
Although it is considered bad practice, you don't have towrite the brackets if there is only one
instruction in the Ifstatement:
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 Afternoonn";
In Perl, you can also write the condition after the instructionitself. For instance:
Similarly, you can define an else block of instructions,which will be executed if the
condition is not met:
print"time is $timen";
if ($time > 12) {
print "GoodAfternoonn";
}
else {
print "Good Morningn";
}
Sometimeyoumaywanttodosomethingdependingonmorethanone
condition.OfcourseyoucanalwaysdefineIfstatementwithin
others,butyoucanalsouseelsif,asacontractionofelse,
if(somethingelse..):
Unless-statements
InPerl,youcanusetheUnlessstatement.Itbehavesexactly
liketheIfstatementbutexecutesthecodeiftheconditionis
notmet.ForinstancethefollowingcodeprintsGoodnightif
it'smorethan11pm:
print "Good nightn" unless($time < 11pm);
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 < 3) {
print "Hellon";
$i = $i + 1;
}
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 "Hellon";
$i = $i + 1;
}
For loop
A starting assignment
A condition
An incrementation
A set of 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
printsHello three times:
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 "Hellon";
}
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:
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;
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.
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:
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:
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:
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.
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:
There are many ways to read the content of a file. Here are thetwo most common ways in Perl.
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):
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.
LESSION 4
In the previouslesson we learnt about If statements and loops. We also started tostudy how to open files and how to write and
read into them. In thislesson we will learn how to compare strings and we will study someadvanced techniques for parsing files.
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:
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):
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":
=~ /Ends with$/
By adding a $ sign in the end of the expression you can change themeaning of the operator from
"contains" to "endswith":
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" !~ "wwt"returns true because hello world does not contain
wwt.
When you use the =~ operator you test the matching of a stringwithin another, this is always
case sensitive. For instance:
If you want to make the =~ operator insensitive, add an iafter the expression:
"hello world" =~ /world/ireturns 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
tosubstitute.
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:
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.
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.
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):
#go to the nextline unless the name starts with "Mr "
next unless$name =~ /^Mr /;
print"$namen";
}
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.
LESSION 5
In the previous lesson we learnt about string comparisons and fileparsing. In this lesson we'll see how Perl can interact with
thefilesystem and execute commands in the Linux operating system. We'llthen use what we've learnt to write a little script.
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");
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.
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";
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:
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:
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:
rename
rmdir
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 "/home/clem/program.pl";
interface=eth2
type=dhcp
proxy=none
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";
$network = $1;
$networkFile = "./networks/$network";
while ($line = ) {
chomp $line;
if ($type eq "dhcp") {
system("dhclient");
if ($gateway ne "none") {
if ($dns ne "none") {
system($strNameServer);
}
}
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.
LESSON 6
A good developer is a lazy developer. In IT, laziness is a gift (would you believe). If you've done something before you should not
have to do it again. Or else, maybe it's time to write a script or some lines of code to automate the process so that you won't
ever have to do it again. A good developer spends a lot of time thinking about his tools, and constantly improves his
environment by developing scripts and tools that will help him develop faster.
In the previous lessons we've used a lot of functions that were built-in the language. For
instance, we used "split", "print", "chomp" ...etc. What we haven't done yet, is to define our own
functions. In Perl we call them subroutines.
Subroutines
A subroutine is basically a few lines of code you give a name to. You can then run these lines by
simply calling the subroutine from your script. You can pass arguments from the scripts to the
subroutine, and depending on the subroutine it can return a result or not.
If you've never used any programming language before, you probably don't know what to think
right now. But don't worry, it's very simple. Let's look at an example to make things a little bit
clearer.
As you probably guessed, this script does something pretty stupid. It shows you the lines which
contain "house" and then the lines which contain "dog" within the file /etc/myProgram/myFile.
It's not what it does that is shocking though, it's how it does it.
Look at the code. It does exactly the same thing twice... once for "house" and once for "dog". If
there was a bug in the way it shows the lines containing "house", would I remember to also fix
the same bug for "dog" when I fix it? Of course not, I'm only human after all.
The idea is simple. Instead of showing the lines which contain "dog" or "house", we'll define a
subroutine which can show lines containing "something". And then we'll call this subroutine
with "dog" and "house".
As you can see, we reduced the amount of code and more importantly, we removed code that
was repeated twice. The first part of the script defines a subroutine called showLines. The
second part simply calls it twice, once giving it the argument "house", and then giving it the
argument "dog".
Within the subroutine, we simply replaced the references to "dog" and "house" with a variable
representing the argument. When you call a subroutine with an argument or a list of arguments,
the subroutine is executed and the arguments are stored in the following array variable: @_.
The line my ($keyword) = @_; is simply assigning the values of the arguments to an array
containing variables. In this case the value of the argument is assigned to $keyword, which
receives "house" and then "dog" when called from the script.
Local variables
The reason why the assignment is preceded by "my" is because we want the $keyword variable
to be local to the subroutine. When a variable is defined with the keyword "my"it becomes a
local variable and it only exists within the subroutine. This way, we do not have to worry
whether or not another variable with the same name is defined in the script. It's always a good
idea to make variables local inside your subroutine, so always declare them with the "my"
keyword.
arguments
Let's go further. Instead of a subroutine which prints the lines containing "something" from the
file /etc/myProgram/myFile, we'll define a subroutine which prints the lines containing
"something" from "some" file. This time we'll use two arguments: the file to look into and the
keyword to search for.
We could even define a subroutine which searches for a keyword in a list of files. For this we
would pass two arguments: a keyword, and an array containing filenames.
In this example, note how the subroutine retrieves the arguments. The array @_ initially
contains two objects, a scalar and an array. By using the "shift" Perl function we retrieved and
deleted the first element of the array and assigned it to the local variable $keyword. We're then
left with @_ only containing the array of filenames.
Returning something
Subroutines can return values. In our previous example, our subroutine was returning nothing.
We were simply calling it and it was outputting some lines on the screen. In this example, we'd
like the subroutine to do the same, but also to count the number of lines it found and to return it.
As you can see, the subroutine simply returns the number of lines by using the "return"
keyword. In the script, the return value is assigned to the variable $nb.
Conclusion
Thanks to subroutines you can now define code which can be called more than once. Through
the use of arguments and return values, you can make your subroutines more flexible. By
extracting common behavior and defining it within subroutines you'll reduce the cost of
maintenance in your scripts and the number of eventual bugs it might contain. In most cases this
will also make your scripts more scalable. In the next lesson we'll look at how to define our
subroutines outside of our script, so that they can be called and used by more than one script.