590 likes | 683 Views
Advanced UNIX. 240-491 Special Topics in Comp. Eng. 1 Semester 2, 2000-2001. Objectives of these slides: introduce Perl (version 4.0-5.0) mostly based on Chapter 1, Learning Perl. 8. Introduction to Perl. Overview. 1. Starting with Perl 2. I/O 3. If-else 4. while 5. Arrays (lists).
E N D
Advanced UNIX 240-491 Special Topics in Comp. Eng. 1Semester 2, 2000-2001 • Objectives of these slides: • introduce Perl (version 4.0-5.0) • mostly based on Chapter 1, Learning Perl 8. Introduction to Perl
Overview 1. Starting with Perl 2. I/O 3. If-else 4. while 5. Arrays (lists) continued
6. Handling Varying Input 7. Subroutines 8. File Processing 9. Reporting 10. Using the UNIX DBM Database 11. The Web and Perl
1. Starting with Perl • Practical Extraction and Report Language • Larry Wall, from 1987 • Features combine shell, awk, many UNIX tools, C libraries (all coded in Perl). • Emphasis on string manipulation, table generation, REs, excellent libraries • especially good Internet/Web libraries continued
On many platforms; free • Many man and info pages. • Many newsgroups (e.g. comp.lang.perl) • Perl v.5 • OOP, more REs, modules • backward compatible with v.4 • check your version by typing: $ perl -v
1.1. Books • Learning PerlRandal L. Schwartz & Tom Christiansen O'Reilly, 1997, 2nd ed. • Programming PerlLarry Wall & Randal L. SchwartzO'Reilly, 2000, 3rd ed. • not easy to read, more of a reference text In our library
1.2. Web Resources • The main Perl site: http://www.perl.com • current Perl version, documentation, libraries (CPAN), FAQs, tools and utilities, features • reference sections on: • applications (e.g. games, graphics), Web, networking, system admin, etc. continued
Resources about Perl • e.g. tutorials, manuals, Web-related, recommended books, example scripts • http://hem.fyristorg.com/gumby/ computing/perl.html • A beginner's Guide to Perl • http://home.bluemarble.net/~scotty/Perl/
1.3. Hello World (hw.pl) $ cat hw.pl#!/usr/bin/perlprint "Hello, world!\n";$ chmod u+x hw.pl$ hw.plHello, world! Or: $ perl hw.pl
2. I/O #!/usr/bin/perl# hm.plprint "What is your name? ";$name = <STDIN>;chop($name);print "Hello, $name!\n"; $ perl hm.pl What is your name? andrew Hello, andrew! $
3. if-else #!/usr/bin/perl# ch.plprint "What is your name? ";$name = <STDIN>;chop($name);if ($name eq "Randal") { print "Hello, Sir Randal!\n";} else { print "Hello, $name!\n"; # ordinary}
4. while Guess the secret word #!/usr/bin/perl# sword.pl$secretword = "llama";print "What is your name? ";$name = <STDIN>;chop($name);if ($name eq "Randal") { print "Hello, Sir Randal!\n";} : Not very secret continued
else { print "Hello, $name!\n"; # ordinary print "Secret word? "; $guess = <STDIN>; chop($guess);while ($guess ne $secretword) { print "Wrong, try again: "; $guess = <STDIN>; chop($guess); }} $ perl sword.pl What is your name? andrew Hello, andrew! Secret word? foobar Wrong, try again: llama $
5. Arrays (lists) @words = ("camel", "llama", "oyster"); $words[0] is"camel" • List variables begin with @ • e.g. @words • $words[0] is a value in the list, so uses $
swords.pl Guess the secret word (v.2) #!/usr/bin/perl@words = ("camel", "llama", "oyster"); print "What is your name? ";$name = <STDIN>;chop($name);if ($name eq "Randal") { print "Hello, Sir Randal!\n";} : An array of secret words continued
else { print "Hello, $name!\n"; # ordinary print "Secret word? "; $guess = <STDIN>; chop($guess); $i = 0; # index into @words $correct = "maybe"; # dummy value : continued
The user can win by guessing any of the secret words. while ($correct eq "maybe") { if ($words[$i] eq $guess) { # right? $correct = "yes"; } elsif ($i < 2) { # some words left? $i = $i + 1; } else { print "Wrong, try again: "; $guess = <STDIN>; chop($guess); $i = 0; # start words again }} }
Usage $ perl swords.pl What is your name? andrew Hello, andrew! Secret word? foo Wrong, try again: bar Wrong, try again: llama $ one of the secret words
5.1. Associative Arrays (tables) • Person Secret Wordfred camelbarney llamabetty oysterwilma oyster • %words = ("fred", "camel", "barney","llama", "betty", "oyster", "wilma", "oyster"); • $words{"betty"}is "oyster" • Associative array variables begin with % • e.g. %words • $words{"betty"} is a value in the list, so uses $
swords2.pl Each user has their own secret word #!/usr/bin/perl%words = ("fred","camel","barney","llama", "betty", "oyster", "wilma", "oyster");print "What is your name? ";$name = <STDIN>;chop($name);if ($name eq "Randal") { print "Hello, Sir Randal!\n";} : continued
else { print "Hello, $name!\n"; # ordinary $secretword = $words{$name}; # get secret word print "Secret word? "; $guess = <STDIN>; chop($guess); while ($guess ne $secretword) { print "Wrong, try again: "; $guess = <STDIN>; chop($guess); }}
Usage $ perl swords2.pl What is your name? barney Hello, barney! Secret word? oyster Wrong, try again: foobar Wrong, try again: llama $ barney's secret word!
5.2. Adding a Default Secret Word ... $secretword = $words{$name}; if ($secretword eq "") { # not found! $secretword = "groucho"; } print "Secret word? ";...
6. Handling Varying Input • sword.pl (and others) treats "Randal" in a special way. • But: "Randal L. Schwartz"or "randal"is treated like other users.
6.1. Replace eq by =~ and RE REs are one of the big advantages of Perl ...if ($name =~ /^Randal/) { # it matches, do something} else { # no match, do something else}...
6.2. Extended REs • Check for a word boundary with \b • Ignore case with the i option (after the last /)
Part of final1.pl ...if ($name =~ /^randal\b/i) { # matches "Randal...", "ranDAL..." print "Hello, Sir Randal!\n";} else { # no match, do something else}...
6.3. Substitution and Translation • Substitution: find and replace(like s/../../ in vi). • Translation: map characters to others(like tr)
...print "What is your name? ";$name = <STDIN>;chop($name);$name =~ s/\W.*//; # Get rid of everything # after first word.$name =~ tr/A-Z/a-z/; # Make lowercase.if ($name eq "randal") { print "Hello, Sir Randal!\n"; }... e.g. Dr.Andrew Davison becomes dr
7. Subroutines Not a good feature sub good_word { # used in final1.pllocal($somename, $someguess) = @_; # input arguments $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if ($somename eq "randal") 1 # return true } elsif (($words{$somename} || "groucho") eq $someguess) { 1; } else { 0; # return false }} # end of subroutine
Called in final1.pl: ... print "Secret word? "; $guess = <STDIN>; chop($guess); while (! &good_word($name, $guess) ) { print "Wrong, try again: "; $guess = <STDIN>; chop($guess); }} Don't forget the &
8. File Processing • Read words from the "wordslist" file: sub init_words { # used inside final1.plopen(WORDSLIST, "wordslist"); while ($name = <WORDSLIST>) { chop($name); $word = <WORDSLIST>; chop($word); $words{$name} = $word; }close(WORDSLIST);}
wordslist Format fredcamelbarneyllamabettyoysterwilmaoyster The code treats the file as four pairs: name secret-word
Called in final1.pl: #!/usr/bin/perl&init_words;print "What is your name? ";$name = <STDIN>;chop($name);...
8.1. File Tests -M is the file's modification date sub init_words { # second version open(WORDSLIST, "wordslist");if (-M WORDSLIST > 7) { die "Sorry, wordslist is too old"; } while ($name = <WORDSLIST>) { chop($name); $word = <WORDSLIST>; chop($word); $words{$name} = $word; } close(WORDSLIST);}
8.2. The open() Command • Similar to popen() in C • the command argument is executed and can be written to via an output stream • In good_word: ...open(MAIL, "| mail dandrew@ratree.psu.ac.th");print MAIL "bad news $somename guessed $someguess\n";close(MAIL);... mail MAIL
8.3. Filename Expansion Also called filename globbing • Assume several files of secret words: • ad.secret, yuk.secret • Modify init_words() to read in all of these • but only if the files are less than 7 days old • Store in the %words associative array
filename expansion sub init_words { # third version while ($filename = <*.secret>) { open(WORDSLIST, $filename); if (-M WORDSLIST < 7) { while ($name = <WORDSLIST>) { chop($name); $word = <WORDSLIST>; chop($word); $words($name) = $word; } } close(WORDSLIST); }}
8.4. The Password File • A typical password line: ad:x:42497:100:Dr.Andrew DAVISON,,,: /home/ad:/bin/bash • the user's details are in the 5th field • the GECOS field • $< always contains the user's ID number (UID)
There is a getpwuid() in C which does the same thing #!/usr/bin/perl# final1.pl&init_words;@password = getpwuid( $< ); # get password data using the UID$name = $password[6]; # get the GECOS field (6th in Perl!)$name =~ s/,.*//; # throw away everything # after 1st comma if ($name =~ /^randal\b/i) { print "Hello, Sir Randal!\n";}...
9. Reporting • secret.pl: • list the *.secret files in the format:filename user-name secret-word
secret.pl #!/usr/bin/perlwhile ($filename = <*.secret>) { open(WORDSLIST, $filename); if (-M WORDSLIST < 7) { while ($name = <WORDSLIST>) { chop($name); $word = <WORDSLIST>; chop($word);write;# invoke STDOUT format } } close(WORDSLIST);} continued
STDOUT Format Definition format STDOUT =@<<<<<<<< @<<<<<<<<< @<<<<<<<<<<<$filename, $name, $word. field definition line field value line continued
Top of Page Format • Used every 60 lines by default: format STDOUT_TOP =Page @<< # field definition line$% # number of pages printedFilename Name Word=========== ======= ========.
Output The *.secret files may need to be 'touched'. $ secret.plPage 1Filename Name Word============= ======= ========ad.secret andrew f1ad.secret paul f2ad.secret dr foobaryuk.secret jim c1yuk.secret bob c2$
10. Using the UNIX DBM Database • In final1.pl, the time of the most recent correct guess is stored in %last_good $last_good{$name} = time; • Problem: %last_good will be lost when the script terminates. • Solution: store %last_good in a DBM database.
Revised final1.pl rw for everyone ...dbmopen(%last_good, "lastdb", 0666);$last_good{$name} = time;dbmclose(%last_good);... returns time in seconds since 1/1/1970
Using final1.pl • $ final1.plHello, Dr.Andrew DAVISON!What is the secret word? bingoWrong, try again. What is the secret word? foobar$ foobar is the secret word for dr (see slide 45)
List the Last Guessses (ex_last.pl) #!/usr/bin/perldbmopen(%last_good,"lastdb",0666);foreach $name (sortkeys(%last_good)) { $when = $last_good{$name}; $hours = (time - $when) / 3600; # compute hours ago write; # use STDOUT format}format STDOUT =User @<<<<<<<<<<<<: last correct guess was @<<< hours ago.$name, $hours.
Output last year, when my user details were different $ ex_last.plUser Andrew DAVIS: last correct guess was 2066 hours ago.User Dr.Andrew DA: last correct guess was 0.07 hours ago.$