• Aucun résultat trouvé

[PDF] Cours PDF pour débuter et progresser en Perl - Free PDF Download

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Cours PDF pour débuter et progresser en Perl - Free PDF Download"

Copied!
27
0
0

Texte intégral

(1)

PERL

Perl stards for Practical Extraction and Reporting Language. The man pages describe it best.

"Perl is a language optimized for scanning arbitrary text files, extracting information from those text files, and printing reports based on that information. It's also a good language for many system management tasks. The language is intended to be practical (easy to use, efficient, complete) rather than beautiful (tiny, elegant, minimal).

Perl combines (in the author's opinion, anyway) some of the best features of C, sed, awk, and sh, so people familiar with those languages should have little difficulty with it. (Language historians will also note some vestiges of csh, Pascal, and even BASIC-PLUS.) Expression syntax corresponds quite closely to C expression syntax. Unlike most Unix utilities, Perl does not arbitrarily limit the size of your data--if you've got the memory, Perl can slurp in your whole file as a single string. Recursion is of unlimited depth. And the tables used by hashes (sometimes called "associative arrays") grow as necessary to prevent degraded performance. Perl can use sophisticated pattern matching techniques to scan large amounts of data very quickly. Although optimized for scanning text, Perl can also deal with binary data, and can make dbm files look like hashes. Setuid Perl scripts are safer than C programs through a dataflow tracing mechanism which prevents many stupid security holes.

If you have a problem that would ordinarily use sed or awk or sh, but it exceeds their capabilities or must run a little faster, and you don't want translators to turn your sed and awk scripts into Perl scripts. "

--man perl

Let's not waste any more time flapping our gums. It's code'n time!

We tested everything out on a system using Redhat 6.0 with Kernel 2.2.5-15. The Web server was Apache 1.3.6 with the Perl modules all set up.

The first thing we'd like you to do is create a directory called /pjunk. Create it anywhere you want, it's just something to hold the junk code you'll be writing. Yup! you'll be churning out proper tripe before the day's out!

Now start up the browser of your choice and type in 127.0.0.1 or localhost or localhost.localdomain. All of them point to the same location, your own machine.

When you now press Enter, your browser will connect to the Web Server, in this case Apache, running on your local machine and will ask for the default file. This file resides in /home/httpd/html (or whatever directory you set as the root directory when you installed Apache) and is named index.html. Apache picks up this file and sends it to your browser, which then displays it, informing all and sundry that 'It Worked!'.

Start up a terminal window and 'cd' your way to this directory. Use your favorite text editor to make a file 'a.pl' and save it to this directory.

a.pl

(2)

Now go back to the browser and type in '127.0.0.1/a.pl', press Enter and what do you see? the contents of the file a.pl listed on your screen.

This isn't exactly what we had in mind. We want the Perl program a.pl to execute when type it's name in, not have it displayed by Netscape!

It seems that if you place your Perl program in any old directory, Apache will treat it as a normal text file. When asked for it, it will pick it up and shoot it across to your browser, without trying to run it or do anything at all with it.

Let's try a.pl out with Perl. bash# perl a.pl

syntax error at a.pl Line 1, near "Type:"

Execution of a.pl aborted due to compilation errors. No good. It barfs all over us.

Let's try this bash# ./a.pl

bash: ./a.pl: Permission denied It refuses to run. This we can solve.

bash# ls -l a.pl

-rw-r--r-- 1 root root 46 Sep 7 18:03 a.pl

The r, w and -'s on the extreme left are file permissions. Everyone on a UNIX system belongs to three groups viz a viz a file. You are either it's creator, or you belong to a relevant group or you're a total outsider. The - on the extreme left tells you about the nature of the file, the three characters after that explain what the owner of the file can do with it. He can either (r)ead from it, (w)rite to it or e(x)ecute it. In the same way, the next three characters show what a person belonging to the same group as the owner can do with the file and the last three characters show what everyone on the system can do with the file.

In this case, the owner can read from and write to his file and everyone else can read from it. However, no one has execute permission. Let's remedy that.

bash# chmod +x a.pl bash# ls -l a.pl

-rwxr-xr-x 1 root root 46 Sep 7 18:03 a.pl Now everyone has permission to execute this file. Let's do just that. bash# ./a.pl

./a.pl: print: command not found

This looks suspicious. What's happening here is that instead of Perl running the file and spitting out an error, our shell BASH assumes that this is a shell script and attempts to run it. Since it isn't, BASH trips over its own feet and prints an error.

(3)

What we need to do is tell BASH to run Perl when we try to execute a.pl. We do that by modifying a.pl as shown below. a.pl

#!/usr/bin/perl

print Content-Type:text/html

In a shell script, a '#' is usually used to mark a comment. But when it's followed by a '!', it's an instruction to the shell telling it to run the program specified and to pass the contents of the file to it.

bash# ./a.pl

syntax error at a.pl Line 1, near "Type:" Execution of a.pl aborted due to compilation errors.

Ah yes, a familiar error message. It seems that Perl is being called now. Things still don't work though, but we'll get to that in a moment

copy this file to /home/cgi-bin/ and get back to your browser. Type in

127.0.0.1/cgi-bin/a.pl and press Enter.

Apache reads your trashy code, giggles wildly, slams you with an Internal Server Error and then politely tells you to contact the server admin.

Apache isn't crass enough to scream to all the world that you don't know how to program using Perl. It receives an error message from Perl and so it sends a polite error page across.

Change a.pl to look like this. a.pl

#!/usr/bin/perl

print "Content-Type:text/html"

All we need to do is add the "'s and it works! The output if we run it from the shell is bash# ./a.pl

Content-Type:text/htmlbash#

Perl demands that all strings be surrounded by ""'s. There's no arguing with it. It's syntax.

Now let's reload this file from the browser. No luck, Apache still isn't satisfied so we must be doing something wrong. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"

Save the file and reload the page in the browser. We're still getting an error, but it's a different one this time. Netscape tells us that the 'document contains no data' and would we try again later?

(4)

The reason we get this error is because Netscape expects every HTML page to contain data. A proper HTML page is made up of two sections, the header and the actual data. Our Perl program just sends a single line of the header (containing the MIME type) across. This line tells the receiving browser that the data to follow is of type text/html and to treat it as such. When Netscape receives nothing after the header, it suspiciously flags an error and shows a warning message box. If you try this with a more laid back browser like Lynx, you're shown a blank page and nothing more.

The two '\n's tell the browser that the headers have ended. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n" print "hi"

Type in the new line and test the program at the prompt bash# ./a.pl

syntax error at ./a.pl line 3, near "print" Execution of ./a.pl aborted due to compilation errors

This error is rather easy to get rid of. It's another syntaxical gaffe of ours. All lines must end with a ';' in Perl, except the very last one. That's why our one line program worked without a semi-colon. Just add the missing semi-colon.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print "hi"

Now the program will work just fine, from both the shell and the browser. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print "hi ";

print "bye";

As far as the semi-colon issue goes, we'll just stick to putting them after all our statements, a la C.

This program goes one step further than the earlier one by having two print statements instead of one. You'd expect the plesantries to appear on two lines, but on both your browser and the shell, they'll be squashed together on one.

Let's try this out. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print "hi\n";

(5)

Getting warm now. When run as a Perl script from the shell, the output is separated by a newline, but you'll still see the two words on the same line in your browser.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print "hi<p>";

print "bye";

Now this is the exact opposite. Under the shell, you're simply shown the contents of the print statements on a single line. As displayed by your browser however, they will appear on two distinct lines.

Just one more to drum the point in. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print "<h1>hi</h1>";

print "bye";

Now the 'hi' will be shown in a larger font on your browser.

All this goes to show that you can put any HTML tag in the print statement and when seen through the eyes of a browser, they will be interpreted and accepted as such. What we're doing through these simple programs is actually _constructing_ Web pages on the fly. A more complicated version of this happens when you go to any search engine. The page with your results on it is created on the server by a program, and then sent across to you. You can also grab a file off the disk and shoot it across, but we'll deal with that a little later.

Now lets delve a little deeper into the innards of Perl. Try this. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print "hi $i bye";

You'd expect to be shown the string 'hi $i bye' but you'll get 'hi bye' instead.

Anything in Perl that starts with a '$' is special. It's a variable. A variable is an entity that can hold a single, changeable value. But to use a variable you have to \idefine\i it first and we haven't done that yet. Since this variable has no assigned value, Perl simply gives it a Null value which means it has no value at all. Unlike other programming languages, Perl doesn't start spitting out errors when it finds variables floating in mid air, as it were. It just tries to guess the right response and move along with the flow. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; $i = "hi bye"; print $i;

(6)

same time.

So this little script will print 'hi bye' at both the shell and through the browser. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; $i = "hi bye"; print $i; $i = "bye"; print $i; $i = 100; print $i;

This is a fairly simple program that demonstrates that a variable's value is, well, variable. We can change it to anything we like. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; $i = 100; print "$i <p>"; $i = $i + 7; print "$i <p>"; $i = $i + 1; print "$i <p>"; $i++; print "$i <p>";

Here's proof that Perl can do math. We first assign '$i' the value 100, print it out (remember, the value of the variable will be printed out, not the string '$i'). Then we add '7' to the current value of '$i', making it 107. We then add '1' making it 108 and finally we do a '$i++' which is simply shorthand for the longer '$i = $i + 1'. The final print prints out 109.

So much for variables. On to more substantial fare. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; if (1) { print "True<p>"; } if (0) { print "False<p>"; }

Control statements add intelligence to your programs and give them the ability to make decisions. The IF statement is one of the most important and basic control statements to be found in any programming language.

(7)

if (1) {

print "True<p>"; }

The value that IF is to test is always in ()'s. In this case it's the number '1' which when used in any decision making statement means TRUE. The pair of {}'s are also compulsory as dictated by the syntax rules. All statements to be executed if the IF statement is found to be TRUE are enclosed within. In this case, all we have is a single print statement.

The second IF statement is identical in structure, except that it test the number '0' which is always FALSE. If, some how, '0' is found to be TRUE, the print statement would churn out 'False'.

Try it out.

You just get to see the True.

That's because only if the result of the IF statement is TRUE will the statements within the {}'s be executed. '0' (which is _always_ FALSE) is never going to equal TRUE, so the contents of the second IF statement are never executed.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; if (4 > 8)

{

print "4 > 8 is never true<p>"; }

if (4 < 8) {

print "4 < 8 is always true<p>"; }

Here's another one in a similar vein to clear things up. Only the contents of the second IF statement will be executed. That's because the number '4' will _never_ be larger than '8'; it's always smaller and that's why the second IF statement is executed. #!/usr/bin/perl

print "Content-Type:text/html\n\n"; if (4 > 8)

{

print "4 > 8 is never true<p>"; }

else {

print "the else<p>"; }

Instead of using two IF's we can use an ELSE. If the IF statement is not TRUE (as it isn't in this case), the ELSE will be executed. It's just like a statement of fact in English. "If this is true, do it, or else do this".

a.pl

(8)

print "Content-Type:text/html\n\n"; while ($i <= 10) { print "$i <p>"; $i++; }

Here we have another control statement, the WHILE. WHILE repeats a set of statements (enclosed in {}'s) while the condition within it's ()'s is TRUE.

So while '$i' is less than or equal to '10', the statements will be executed, otherwise not.

In this case '$i' is automatically give a value of '1' instead of a blank value (a Null) because Perl is smart enough to notice that you're using the variable in a mathematical context. Therefor it would make more sense if the value was a number.

So the WHILE will run while the value of '$i' is less than or equal to '10'. The line

$i++;

is vital. If it isn't there then the value of '$i' would never increase and we'll be stuck in the WHILE statement forever! A condition known as an Infinite Loop. Since we're incrementing the value however, the WHILE will run ten times and the values of '$i' from one to ten will be printed out.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; for ($i = 2; $i <=10; $i++)

{

print "$i <p>"; }

A FOR statement is identical in use to a WHILE statement, though the syntax is a little different.

In the FOR, we first set the initial value of '$i' (we \iinitialise\i it) to '2'. After the semi-colon, we then set the condition i.e. the statement should loop while '$i' is less than or equal to the number '10'. After the last semi-colon, we tell the FOR statement what to do with '$i' after every iteration and in this case, we want to increment the value by '1'.

So the print statement prints out the numbers two to ten. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; $i = 30; @a = (6 , "Hi", Bye , $i ); print @a; print "@a";

(9)

variables (called arrays in C and most other languages) that can hold multiple, usually related, values. These variables start with an '@' sign and values are assigned to them in the manner shown above. We don't have to use ""'s to demarcate strings, we can simply write out what we want ( as in the case of the string Bye). We can even have a variable as part of the array. The first print will print out all the values, without any spaces so they appear joined together. The second print will display the values with spaces in between them.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; $i = 30;

@a = (6 , "Hi", Bye , $i );

print "@a[0] , @a[20] , @a[2] , $a[2]"; The output in your browser will be

6,,Bye,Bye

This program shows another way to access the stores values. Look carefully at the print statement. Using '@a[0]' we tell the Perl interpreter to access the _first_ (Perl in this case counts from zero onwards) member of the array. So '6' is displayed. Similarly, we next ask for the twenty first (remember, we're counting from zero) member of the array, which hasn't been defined. Perl doesn't complain. All it does is return a Null. Next, we ask for the third member, and Perl returns 'Bye'. Finally, we demonstrate that we don't have to use '@' to access an array, the good ol' '$' sign will suffice. We get a 'Bye' here too. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; @a = (6 , "Hi", Bye , $i ); print "$#a <p>"; print "@a[0,2] <p>"; print "@a[0..2] <p>"; print "@a[$#a] <p>"; print "@a[-1] Last <p>";

The text displayed in the browser window is 3

6 Bye 6 Hi Bye Last

Notice that we've removed the variable '$i' from the script. The first print will output the total number of members in the array '@a'. That's what the '$#a' means. Next, we have '@a[0,2]', which means output the first and third members. '@a[0..2]' gives us the members in the range zero to 2. So we get the string '6 Hi Bye'. The fourth print is supposed to give us the last member of the array, but since that is a Null ('$i' is no loner initialized to anything), we get nothing. The final print does the same thing, i.e. it accesses the last member of the array. Here too, we get a Null and the word Last.

(10)

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; @a = (6 , "Hi", Bye , $i );

foreach $aa (@a) {

print "$aa <p>"; }

Here's a simple program that prints out all the members of the array '@a'. FOREACH is a reserved word. What happens here is that each time through the loop, '$aa' is assigned the value of a member of '@a', from zero onwards. In other words, foreach iteration of the loop, '@aa' holds the value of the next member in '@a'.

Here's another way to do it. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; @a = (6 , "Hi", Bye , $i );

for $aa (@a) {

print "$aa <p>"; }

It's exactly the same when you use a simple FOR. It's up to you to decide what coding style you wish to follow. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; @a = (6 , "Hi", Bye , $i );

for $aa (0 .. $#a) {

print "$aa $a[$p] <p>"; }

You should be able to guess what this program does just by looking at it. It's simply going over some old ground.

In the FOR loop, we're cycling through the range of values from zero to the last value of the array. Within the loop, we print those values out.

Nothing to it. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; @a = (6 , "Hi", Bye , $i ); for (@a) { print "$_ <p>";

(11)

}

Here's just a little bit of extra information. The variable $_ is a special one. It always holds the last value returned. It's like saying 'print "$aa <p>" in the earlier programs. So here in the loop, the print statement will output a list of all the members in '@a' as the FOR statement loops the loop.

a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; @a = (6 , "Hi", Bye , $i ); for (@a) { print ; }

In fact, you don't need to use the '$_' at all. If you put nothing else after the print, Perl will automatically add the '$_' internally and everything will work as before.

a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; %a = ("a1","b1","c1","d1"); print $a{"a1"}; print $a{"b1"}; print $a{"c1"};

In this program we introduce something new, a _third_ kind of variable! This one's called a 'hash' or a 'hash table' or even an 'associated array' and it's made up of paired values. It's a lot like an array, except that here each member is either a \ikey\i or it's associated \ivalue\i.

This new variable is marked with a '%' sign and the members are initialized as shown. Here, 'a1' is the key member and 'b1' is the associated value. Similarly, 'c1' is the key and 'd1' is the value. They're written out one after the other as shown.

The print statement also has a slightly different format. There's no explaining it; it's syntax and we have to simply accept it as such. The first print will display 'b1' because that's the value of the key 'a1'. Similarly, the last print will display 'd1'. The print in the middle however, will display nothing at all, since 'b1' is a value and not a key. Only the value can be displayed when the key is given, not vice-versa.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; %a = ("a1","b1","c1","d1");

($a,$b) = each (%a); print "$a , $b <p>"; $a,$b = each (%a); print "$a , $b <p>";

Here, in line number four, we're putting the first key into '$a' and it's value into '$b'. So '$a' will contain 'a1' and '$b' will contain 'b1'. We print that out.

(12)

yet) and '$b' contains 'c1', the key. This is definitely not something we want. The lesson as always is, stick to the syntax! a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; %a = ("a1","b1","c1","d1");

while ( ($a,$b) = each (%a) ) {

print "$a , $b <p>"; }

This is a nice clean way to print out all the values. While the loop loops, '$a' and '$b' will keep being given the key and value members respectively and those will be printed out. The loop ends when 'each' reaches the end of the hash table and returns a FALSE. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; %a = ("a1","b1","c1","d1"); @b = keys(%a); print "@b <p>"; @b = values(%a); print "@b <p>";

Here's a straight forward program. The function 'keys()' extracts the names of all the keys in the hash table '%a' and the print displays them. Similarly, the function 'values()' extracts all the values and the next print displays them.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; %a = ("a1","b1","c1","d1");

print %a;

This program outputs a line with the keys and values, one after the other. The values are not separated by spaces. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; %a = ("a1","b1","c1","d1");

print "%a";

This program (surprise!) outputs the text %a

Nothing more. a.pl

#!/usr/bin/perl

(13)

print %ENV;

Check this program out. Quite a lot of text for just one simple line. These are the Environmental variables available to Perl. The hash table %ENV is a special one and is automatically created by the Perl interpreter and is always available for instant use. It contains a lot of information about the environment your script is running in and can be very useful.For now, just gape at the output and be amazed.

a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; foreach $aa (%ENV)

{

print "$aa <p>"; }

This script cleans up the output a bit by inserting a paragraph break after every line of data. It's all beginning to make sense now, isn't it? Look at the output carefully. You can discover the server you're running under, the document root, the IP address of the machine that called you,

all at run time. Useful, this is. a.pl

#!/usr/bin/perl

print "Content-Type:text/html\n\n"; print $ENV{"QUERY_STRING"};

print $ENV{"HTTP_HOST"};

Flashback to the earlier script where we were talking about extracting individual values for every string in a hash table. That's what we're doing here. The first key, 'QUERY_STRING' gives us nothing at all because no parameters have been passed to our script and so this key is empty. The second key, 'HTTP_HOST' holds the address of the client and that's what the print

dutifully displays. Let's try this out...

Create an HTML file with the following text in it and copy it to /home/httpd/html/ and name it a.html

<HTML>

<FORM ACTION="http://127.0.0.1/cgi-bin/a.pl"> <INPUT TYPE=TEXT NAME=aa><P>

<INPUT TYPE=TEXT NAME=bb><P>

<INPUT TYPE=SUBMIT VALUE="click"> </FORM>

</HTML>

Edit our pal a.pl to look like this. #!/usr/bin/perl

print "Content-Type:text/html\n\n"; print $ENV{"QUERY_STRING"};

(14)

Now load on Netscape and go to http://127.0.0.1/a.html. Enter any old rubbish in to the two text boxes on display and click the button named 'click'. You're immediately presented with the output from our Perl script; the text of the 'QUERY_STRING' sent to us by the browser. Examine it closely. If, like me, you typed 'aaa' into the first box and 'bbb' into the second one, you'll get the following.

aa=aaa&bb=bbb

Simple it is, but it's also the heart and soul of CGI programming. What we have here are a list of the text boxes on our HTML page and the data entered into them, separated by ampersands. This is exactly the technique that sites like Yahoo

(www.yahoo.com) use. You enter text into their "Search" text box and the data is passed to a waiting script/program in the server which examines the string and does the needful.

Of course, this string is pretty useless until it can be properly formatted and this is where Perl really shines. Sure, a language like C would be faster, but C just can't handle strings as easily as Perl can. Perl is justifiably famous as one of the best scripting languages around for text handling and not without reason. The next script shows just how easy it is to handle strings in Perl #!/usr/bin/perl print "Content-Type:text/html\n\n"; $a = $ENV{"QUERY_STRING"}; @b = split('=' , $a); print "@b <p>"; foreach $i (@b) { print "$i <p>"; }

What this script does is cut up the 'QUERY_STRING' into members of the array '@b', at the '=' signs. So we end up with 3 members in '@b', "aa" "aaa&bb" and "bbb". Not exactly what we wanted, but we're getting there. Let's try chopping them up at the '&'. #!/usr/bin/perl print "Content-Type:text/html\n\n"; $a = $ENV{"QUERY_STRING"}; @b = split('&' , $a); print "@b <p>"; foreach $i (@b) { print "$i <p>"; }

Just one character has been changed. The '=' in split() has been replaced by a '&'. We get aa=bbb

and bb=bbb

(15)

#!/usr/bin/perl print "Content-Type:text/html\n\n"; $a = $ENV{"QUERY_STRING"}; @b = split('&' , $a); print "@b <p>"; foreach $i (@b) { print "$i <p>"; } foreach $j (@b) { @c = split('=' , $j); foreach $k (@c) { print "$k <p>"; } }

This may look convoluted, but it's actually quite simple. Up until line number 8, everything is familiar. After that, we take the array '@b' which has already been split at the '&' and further splice it at the '='. The inner loop just prints everything out. Nothing to it really; and we get just what we want, all the keys and their values nicely lined up on after another with no intervening ampersands and equal to's.

Onwards now to something a little overdue. Reading from a file. You should be able to decipher this yourself. #!/usr/bin/perl

print "Content-Type:text/html\n\n"; open(aa,"a10.txt");

while ($i = <aa>) {

print $i; }

close(aa);

This is quite straight forward. We use the function 'open()' to open the file of our choice. 'aa' is the name of the \ifile handle\i (a variable that is use by us to refer to the file). In the WHILE statement we loop till we reach the end of the file. FALSE will then be returned and we'll exit out. With in the loop, we're simply printing out the file. Notice that 'aa' is surrounded by <>'s. There's no rationalizing it; it's syntax.

The final statement is the function close() which as the name suggests, closes a file and cleans up after it. #!/usr/bin/perl print "Content-Type:text/html\n\n"; &aa; &aa; print "END <p>"; sub aa() { print "hi<p>"; }

(16)

Here we introduce a new concept. The Subroutine. A subroutine is a quick and easy way to call code that will be repeated in the script. Here we wish to print out the line 'hi' twice. We could either use two print statements one after the other or create a subroutine 'aa()' which prints out the string and call it twice. This example is quite trivial, so it may not make to much sense to use subroutines here, but what if the subroutine was many hundreds of lines of code long. We'd be in trouble without

subroutines then!

Why the '&' before the sub name? You better than to ask! It's syntax of course and there's no explaining it. #!/usr/bin/perl print "Content-Type:text/html\n\n"; $i = &aa; print "$i <p>"; sub aa() { print "hi<p>"; }

This program returns a value, which is stored in '$i'. The return value is the last value that's returned in the subroutine. Here, it's the return value of print (which is 1) which is returned.

#!/usr/bin/perl print "Content-Type:text/html\n\n"; $i = &aa; print "$i <p>"; sub aa() { print "hi<p>"; 21; }

Now the return value will be 21. Simple isn't it? Return values are used to indicate errors or to return the value of a calculation; that sort of thing. You've come across them before. For example, split() returns an array.

a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; &aa(1,2) , "\n"; sub aa() { print $_[0] ,"\n" ; print $_[1] ,"\n" ; }

This script is a continuation of the same theme, but it's a tad more involved. Here we're passing the subroutine '&aa' two parameters. To access these parameters in the subroutine, we use '$_'. Use '$_[0]' for the first one and '$_[1]' for the next. These variables are created for you automatically, by Perl.

a.pl

#!/usr/bin/perl

(17)

&aa(1,2,3) ,"\n"; sub aa() { print @_ , "\n"; foreach $_ (@_) { print $_ , "\n"; } }

Here we first print out the parameters in one long line using '@_' and we then print them out one by one in a foreach loop.'@_' is an array containing the parameters and is created automatically.

a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; print &aa(),"\n"; sub aa() { 6; }

Here's another way to return a number and print out it's value. a.pl #!/usr/bin/perl print "Content-Type:text/html\n\n"; print &aa(1,2,3,4) , "\n"; sub aa() { $s = 0; foreach (@_) { $s += $_; } $s; }

Here's a nice little program that puts everything together for us. We pass the subroutine four parameters. In the subroutine we then initialize the variable '$s' to 0 and use it in the FOREACH loop to add up all the parameter values. FOREACH will loop until all the parameters have been accessed and then it will end. Since we have '$s' as the last value in the subroutine that will be returned as the return value and printed out.

MODULES ^^^^^^^

Up till now, all that we've done is create simple Perl scripts using the predefined functions in Perl. One of the things Perl is justifiably famous for is it's extensibility. By that I don't mean hacking the Perl interpreter. True, it's source code is freely available and if you want to you can do just about anything with it you want. Unfortunately, not too many people in the world have the ability or the patience to go through some million lines of code just to add a new keyword or function!

(18)

No, Perl, gives us a much simpler way to do what we want, modules. Let's figure these beasts out.

x.pl use Env;

print "Home: $HOME\n"; print "Name: $LOGNAME\n"; bash# perl x.pl

Home= /root Name= root

Type in the script as shown into x.pl and then run the program using the perl interpreter. Notice that we're not using the '#!' to call the interpreter, but doing it directly. It's no biggie, you can do things the old way if you want.

The output is shown above.

What this script does is use the module Env to automatically create some variables for our use. We then use these variables in the print statements. Try the same program without the line 'use Env'. The print statements will only have blank lines after the ='s.

x.pl use zzz;

bash# perl x.pl

Can't locate zzz.pm in @INC (@INC contains:

/usr/lib/perl5/5.00503/i386-linux /usr/lib/perl5/5.00503

/usr/lib/perl5/site_perl/5.005/i386-linux /usr/lib/perl5/site_perl/5.005 .) at x.pl line 1.

BEGIN failed--compilation aborted at x.pl line 1.

Let's try using a module of our own, which we'll call zzz. By putting the line 'use zzz' in the Perl script, we're telling Perl to find and load the module into memory and to prepare it for use. Since we haven't yet gotten around to actually creating the module file, Perl spits out a screen full of errors telling us it can't locate the file aaa.pm.

x.pl use zzz; zzz.pm package zzz; $x = 1; bash# perl x.pl <no output>

Right. Now we've created a file named zzz.pm and put the relevant lines into it. the word 'package' tell Perl the name of the package and after that we create a variable and assign it a value. We get no output when we run the file, but no errors either.

(19)

x.pl use zzz; zzz.pm package zzz; $x = 1; print "hi \n"; bash# perl x.pl hi

Okay, here's a line of output. Simple. x.pl use lib './'; use zzz; zzz.pm package zzz; $x = 1; print "hi \n"; bash# perl x.pl hi

In this version of x.pl, we use the line 'use lib './'' precisely state the location of the module file. It could be anywhere on the disk. x.pl use lib './'; use zzz; zzz.pm package zzz; $x = 1; sub xxx { print "Hi in xxx\n"; } bash# perl x.pl <no output>

We're going a little deeper now. We've created a small function name 'xxx' which prints out a line. Notice however, that when we run the script, we get no output. That's pretty obvious to debug, we haven't called this new function from within x.pl! x.pl use lib './'; use zzz; zzz::xxx(); zzz->xxx(); zzz.pm package zzz; $x = 1; sub xxx {

(20)

print "Hi in xxx\n"; }

bash# perl x.pl Hi in xxx

Hi in xxx

We've remedied that here and we get our output. We've actually called the same function twice, using two different styles. They both mean the same thing, it's just a matter of personal preference which one you decide to use in the end.

x.pl use lib './'; use zzz; zzz::xxx(); zzz.pm package zzz; sub xxx { print "Hi in xxx\n"; } bash# perl x.pl

zzz.pm did not return a true value at x.pl line 1. BEGIN failed--compilation aborted at x.pl line 1.

Who would have thought that removing one simple variable. which we don't even use, would have given us an error. It seems that our package must always exit out with an acceptable return value. So let's not quibble and give Perl what it wants.

x.pl use lib './'; use zzz; zzz::xxx(); zzz.pm package zzz; sub xxx { print "Hi in xxx\n"; } 1; bash# perl x.pl Hi in xxx

That's all that was required. A single return value. x.pl

use lib './'; use zzz;

zzz::xxx(); zzz.pm

(21)

package zzz;

BEGIN {print "start\n";} sub xxx { print "Hi in xxx\n"; } 1; bash# perl x.pl start Hi in xxx

The BEGIN is called a constructor and is the first thing called when you say 'use zzz' in x.pl. It can be used by your script to initialize things before any other function is called or variable is accessed.

x.pl use lib './'; use zzz; zzz::xxx(); zzz.pm package zzz;

BEGIN {print "start\n";} sub xxx

{

print "Hi in xxx\n"; }

END {print "over\n";} 1;

bash# perl x.pl start

Hi in xxx over

Similar in concept to the constructor, we have the destructor, END, which is the last thing called before the module ends. It is supposed to clean up after the rest of the module.

Of course, you needn't do all of this by hand. A nifty little program

named h2xs makes most of the framework automatically. Check it out below. Try this out. Go to the directory of your choice, /pjunk for example and type this in.

(22)

bash# h2xs -A -n VMCI You'll get these lines on your screen. Writing VMCI/VMCI.pm Writing VMCI/VMCI.xs Writing VMCI/Makefile.PL Writing VMCI/test.pl Writing VMCI/Changes Writing VMCI/MANIFEST Now say bash# ls -l total 15

drwxr-xr-x 2 root root 1024 Sep 11 12:16 VMCI Hmmm. We have a new directory named VMCI. Let's 'cd' into it. bash# cd VMCI

bash# ls -l total 6

-rw-r--r-- 1 root root 117 Sep 11 12:16 Changes -rw-r--r-- 1 root root 53 Sep 11 12:16 MANIFEST -rw-r--r-- 1 root root 369 Sep 11 12:16 Makefile.PL -rw-r--r-- 1 root root 1008 Sep 11 12:16 VMCI.pm -rw-r--r-- 1 root root 91 Sep 11 12:16 VMCI.xs -rw-r--r-- 1 root root 649 Sep 11 12:16 test.pl Now lets edit the file VMCI.xs in a text editor. Use any you like. VMCI.xs

#include "EXTERN.h" #include "perl.h" #include "XSUB.h"

MODULE = VMCI PACKAGE = VMCI

This is the framework that h2xs automatically creates so that you don't have to type it in. Add the following lines to the file after the line with MODULE = VMCI.

void hello() CODE:

printf("Hello\n");

(23)

Now exit back to the shell and type in the following at the prompt. bash# perl Makefile.PL

The following will be displayed.

Checking if your kit is complete... Looks good

Writing Makefile for VMCI Now type this in.

bash# make

This calls the resident C compiler which starts to compile the code. mkdir blib mkdir blib/lib mkdir blib/arch mkdir blib/arch/auto mkdir blib/arch/auto/VMCI mkdir blib/lib/auto mkdir blib/lib/auto/VMCI mkdir blib/man3 cp VMCI.pm blib/lib/VMCI.pm

AutoSplitting blib/lib/VMCI.pm (blib/lib/auto/VMCI)

/usr/bin/perl -I/usr/lib/perl5/5.00503/i386-linux -I/usr/lib/perl5/5.00503 /usr/lib/perl5/5.00503/ExtUtils/xsubpp -typemap

/usr/lib/perl5/5.00503/ExtUtils/typemap VMCI.xs >xstmp.c && mv xstmp.c VMCI.c cc c Dbool=char DHAS_BOOL I/usr/local/include O2 DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" -fpic -I/usr/lib/perl5/5.00503/i386-linux/CORE VMCI.c Running Mkbootstrap for VMCI ()

chmod 644 VMCI.bs

LD_RUN_PATH="" cc -o blib/arch/auto/VMCI/VMCI.so -shared -L/usr/local/lib VMCI.o chmod 755 blib/arch/auto/VMCI/VMCI.so

cp VMCI.bs blib/arch/auto/VMCI/VMCI.bs chmod 644 blib/arch/auto/VMCI/VMCI.bs Manifying blib/man3/VMCI.3

Now type

bash# make install

to actually install the module. Notice where it's being copied.

Installing /usr/lib/perl5/site_perl/5.005/i386-linux/auto/VMCI/VMCI.so Installing /usr/lib/perl5/site_perl/5.005/i386-linux/auto/VMCI/VMCI.bs

(24)

library tree!

Installing /usr/lib/perl5/man/man3/VMCI.3

Writing /usr/lib/perl5/site_perl/5.005/i386-linux/auto/VMCI/.packlist

Appending installation info to /usr/lib/perl5/5.00503/i386-linux/perllocal.pod

That's it! We're done. Now to test out the module. Create a file called 'hello.pl' containing the following Perl code.

hello.pl

#! /usr/bin/perl use lib './blib' ; use VMCI;

VMCI::hello();

Now run it from the prompt. bash# perl hello.pl Hello

It works! That's all there was to it. This is how we can extend Perl using modules written in C rather than Perl. So we can now pretty much to whatever it is that C can do, in the warm and freindly confines of Perl.

Here is the .pm file that's automatically created for us. Notice the difference in size and complexity, yet it does pretty much what we've been doing in a couple of lines.

package VMCI; use strict;

use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter;

require DynaLoader; require AutoLoader;

@ISA = qw(Exporter DynaLoader);

# Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT = qw(

);

$VERSION = '0.01';

bootstrap VMCI $VERSION; # Preloaded methods go here.

# Autoload methods go after =cut, and are processed by the autosplit program. 1;

__END__

# Below is the stub of documentation for your module. You better edit it! =head1 NAME

(25)

=head1 SYNOPSIS use VMCI;

blah blah blah =head1 DESCRIPTION

Stub documentation for VMCI was created by h2xs. It looks like the author of the extension was negligent enough to leave the stub unedited.

Blah blah blah. =head1 AUTHOR

A. U. Thor, a.u.thor@a.galaxy.far.far.away =head1 SEE ALSO

perl(1). =cut

Now the implications of modules should be quite clear. Let's examine anexample of modules in action and how they can make life easier for us. One of the many things Perl is used for in a Website is to accept registration forms and to add the information to a database. Now, if we had to, we could have used a simple text file as the database and kept adding new data to it. That's a clunky approach, but one we'd have had to adopt. The only other alternative would have been to write out own C modules that would talk to a full commercial database like Oracle or Postgresql or MySql. Lots o' work, that!

But fear not! The tough stuff has already been done by someone else. Yes, ladies and gentlemen, there already exists a library of modules, called the DBI (DataBase Interface) modules that can talk to almost every RDBMS in existence. You no longer have to struggle with them yourselves, all you have to do is talk to DBI and it'll do the needful. Check out the following programs. a.pl #!/usr/bin/perl $host = " "; use DBI; $dbh = DBI->connect("DBI:mysql:test:$host"); $dbh->do("CREATE TABLE z5 (vno char(10))");

This is really simple. We first create a variable named '$host' and make it hold a space. In the next line we say 'use DBI' to use the DBI modules.

We then call a function named 'connect' within the DBI module and pass it certain parameters. The first is the name of the module itself, 'DBI'. The second is the name of the Database we wish to connect to. In our case it's 'mysql' because that's what we're using. If you're using Oracle, you'd put that here. Everything else (and this is the crucial bit) would remain the _same_. The third parameter is the name of the database we wish to use and the final one is the address of the machine on which the RDBMS resides.We're passing it a space to tell DBI that MySql is on our machine, but you could put the address of any machine you wished out here.

Connect will return a number which is the handle to this connection and this handle will be stored in the variable '$dbh'. We then use the handle to call the function 'do' which is passed a string. This string (which in this case is an SQL statement) is sent to the Database specified earlier. We're telling MySql to create a new table name 'z5' and make a single column in it, that of 'vno' which is ten characters

(26)

wide.

That's all that this program does. a.pl

#!/usr/bin/perl $t = "z5";

use DBI;

$dbh = DBI->connect("DBI:mysql:test"); $dbh->do("drop table if exists $t");

Here we connect to the SQL server as usual. Notice that we don't even need to give the host address if the server is on our machine. We send the server the SQL command to drop the table if it exists. That done, we exit.

The only real reason we've done this script is to demonstrate that we can use Perl variables even within the strings to be sent to the Database. The variables are replaced with their values before the string is shot off to the server.

a.pl

#!/usr/bin/perl $t = "z5";

use DBI;

$dbh = DBI->connect("DBI:mysql:test");

$dbh->do("drop table $t") or die $DBI::errstr;

This program demonstrates the concept of error checks. If the table 'z5' cannot be dropped, then the program ends with the error value displayed.

a.pl

#!/usr/bin/perl use DBI;

$dbh = DBI->connect("DBI:mysql:test");

$sth = $dbh->prepare("select * from z5") or die $dbh->errstr; $sth->execute() or die $sth->errstr;

$i=0;

while($row = $sth->fetchrow_arrayref) {

print $row->[0] , "\n"; }

This program really puts things together. The first three lines are familiar by now. In the fourth line, we can a function named 'prepare' and give it the SQL command string as it's only parameter. This function doesn't send the string across, it simply readies it for the trip. It returns a handle, which we store in the variable '$sth'. In the fifth line we use the handle to call the function 'execute'. It's this function which 'executes' the SQL statement by sending it to the server.

In the while loop that follows, we use the function 'fetchrow_array' to retrieve the result, row by row and store it in '$row'. We then print out values of the first (and in this case the only) column in the database.

(27)

Références

Documents relatifs

(a) Request architecture: a User interacts with its Personal Assistant, generating a series of queries that are sent through the Privacy Filter (which sanitizes the user identity) to

Même lorsque des migrants quittent la Roumanie simplement avec une adresse ou même sans contacts personnels mais avec quelques informations glanées dans leur région

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des

The second model, deriving from the main tradition of British constitutionalism, entails that the basic rules and principles of constitutional law should be conceived as the

Le niveau de diplôme joue un rôle apparemment moindre ici que la classe sociale: si pour certains jeunes d’origine populaire les études universitaires rapprochent des classes

Com o objetivo de trabalhar o melhoramento genético do mamoeiro quanto a características morfo- agronômicas e da qualidade do fruto inferências genéticas foram feitas por Marin (2001)

Com o objetivo de gerar genótipos superiores aos atuais (variedades e híbridos), com elevada produtividade, adaptados, resistentes e, ou, tolerantes às principais pragas e doenças,

In this instance, where the solution bounding curve for global correction does not intersect the two limit curves defining the local non-interference domain, the method