Perl Maven Cookbook v0.01

21
Perl Maven Cookbook version 0.01 Gabor Szabo http://perlmaven.com/ Copyright Gabor Szabo Generated Wed May 2 15:28:12 2012

Transcript of Perl Maven Cookbook v0.01

Page 1: Perl Maven Cookbook v0.01

Perl Maven Cookbook

version 0.01

Gabor Szabo

http://perlmaven.com/

Copyright Gabor Szabo

Generated Wed May 2 15:28:12 2012

Page 2: Perl Maven Cookbook v0.01

1. Perl Maven Cookbook

1.1. Copyright and License

Perl Maven Cookbok is Copyright (c) 2012 Gabor Szabo. http://szabgab.com/ http://perlmaven.com/

All source code in Perl Maven Cookbook is available under the same license as Perl 5.14.0 wasreleased. The GPL and the Artisitc license.

The Perl Maven Cookbook can be redistributed without modification and free of charge to individuals.That is. You are free to send it to your friends and enemies one-by-one, as long as you have notmade any changes to the document and you don't charge any money for the document. You are notallowed to mass-dsitribute it to a mailing list or upload to a web site or by any other means.

Copyright (c) 2012 Gabor Szabo

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2

Page 3: Perl Maven Cookbook v0.01

2. Perl Maven Cookbook

2.1. Create Unix user account

examples/applications/create_user.pl

#!/usr/bin/perluse strict;use warnings;

# --fname Foo --lname Bar# /usr/sbin/adduser --home /opt/bfoo --gecos "Foo Bar" bfoo

my $adduser = '/usr/sbin/adduser';

use Getopt::Long qw(GetOptions);

if (not @ARGV) { usage();}

my %opts;GetOptions(\%opts, 'fname=s', 'lname=s', 'run',) or usage();

if (not $opts{fname} or $opts{fname} !~ /^[a-zA-Z]+$/) { usage("First name must be alphabetic");}if (not $opts{lname} or $opts{lname} !~ /^[a-zA-Z]+$/) { usage("Last name must be alphabetic");}my $username = lc( substr($opts{lname}, 0, 1) . $opts{fname});my $home = "/opt/$username";

print "Username: $username\n";

my $cmd = qq($adduser --home $home --gecos "$opts{fname} $opts{lname}" $username);

print "$cmd\n";if ($opts{run}) { system $cmd;} else { print "need to add the --run flag to actually execute\n";}

sub usage { my ($msg) = @_; if ($msg) {

3

Page 4: Perl Maven Cookbook v0.01

print "$msg\n\n"; } print "Usage: $0 --fname FirstName --lname LastName --run\n"; exit;}

2.2. Reporting file system diskspace usage (df)

examples/applications/diskspace.pl

#!/usr/bin/perluse strict;use warnings;

use Filesys::DfPortable qw(dfportable);

#my $df = dfportable("/", 1024 * 1024 * 1024);

my $df = dfportable("/", 1024);print "Total Size: $df->{blocks} K\n";print "Available: $df->{bfree} K\n";print "Used: $df->{bused} K\n";print "Percent Full: $df->{per} %\n";print "Total available to me: $df->{bavail} K\n";

$ perl diskspace.pl ; df /Total Size: 48062440 KAvailable: 38720692 KUsed: 9341748 KPercent Full: 20 %Total available to me: 36279216 K

Filesystem 1K-blocks Used Available Use% Mounted on/dev/sda1 48062440 9341748 36279216 21% /

2.3. Reporting diskspace usage on the mail server

examples/applications/diskusage.pl

#!/usr/bin/perluse strict;use warnings;

## Reporting disk usage on the mail server

4

Page 5: Perl Maven Cookbook v0.01

## Run the script in a cron job## 1) Report to Boss if there are people with large files# # 2) If a user has a file that is too big then ask him to remove the# large e-mail from the mail server via web access# This one has not been implemented yet#######################################################

use Mail::Sendmail qw(sendmail);use Filesys::DfPortable qw(dfportable);

################## Limit Definitions# the size of the /var/spool/mail/username file in bytesmy $report_to_boss_limit = 1_000_000;my $report_to_user_limit = 500_000;my $domain = '@company.com';my $boss_email = '[email protected]';my $from_email = 'Disk Usage Report <[email protected]>';my $disk_space_percantage = 80;

my %file_size;# each user has a file in that directoryforeach my $path (glob "/var/spool/mail/*") { if ($path =~ /Save/) { # disregard the Save directory next; } if ($path =~ /\.pop$/) { # disregard temporary .pop files next; }

$file_size{$path} = -s $path;}

my $txt = "";# sort files by sizeforeach my $path (sort {$file_size{$b} <=> $file_size{$a}} keys %file_size) { my $name = $path; $name =~ s{/var/spool/mail/}{};

if ($file_size{$path} > $report_to_boss_limit) { $txt .= "$name\t\t" . int ($file_size{$path}/1_000_000) . " MB\n"; } if ($file_size{$path} > $report_to_user_limit) { my $msg = "You are currently using $file_size{$path} bytes\n"; $msg .= "Please reduce it to under $report_to_user_limit\n"; sendmail ( To => "$name$domain", From => $from_email, Subject => 'Disk Usage Report' . localtime(), Message => $msg,

5

Page 6: Perl Maven Cookbook v0.01

); }}

my @disks = qw(/ /boot);foreach my $disk (@disks) { my $df = dfportable($disk, 1024); if ($df->{per} > $disk_space_percantage) { $txt .= "\n\nDiskspace is low\n\nUsing "; $txt .= $df->{per} . "\% of the space on $disk\n"; }}

if ($txt) { $txt = "Disk Usage of /var/spool/mail on the incoming mail server\n" . "Reporting users over $report_to_boss_limit bytes\n\n" . $txt; sendmail ( To => $boss_email, From => $from_email, Subject => 'Disk Usage Report' . localtime(), Message => $txt, );}

2.4. A du like script

examples/applications/du.pl

#!/usr/bin/perluse strict;use warnings;

use Filesys::DiskUsage qw(du);

if (not @ARGV) { die "Usage: $0 DIRs\n";}

my %sizes = du({'make-hash' => 1}, @ARGV);foreach my $entry (sort { $sizes{$a} <=> $sizes{$b} } keys %sizes) { print "$entry => $sizes{$entry}\n";}

6

Page 7: Perl Maven Cookbook v0.01

2.5. Send files by e-mail

examples/applications/send_files.pl

#!/usr/bin/perluse strict;use warnings;

use File::Basename qw(basename);use File::Slurp qw(read_file);use Getopt::Long qw(GetOptions);use MIME::Lite;use Pod::Usage qw(pod2usage);

my $text = <<'END_TEXT';<html><head> <title>Hello</title></head><body> <h1>World</h1></body></html>END_TEXT

my %opt;GetOptions(\%opt, 'from=s', 'to=s', 'cc=s', 'subject=s', 'textfile=s', 'smtp=s',) or pod2usage();if (not $opt{from} or not $opt{to} or not $opt{subject} ) { pod2usage();}if ($opt{textfile}) { $text = read_file( $opt{textfile} );}

send_files(\%opt, $opt{subject}, $text, @ARGV);

sub send_files { my ($opt, $subject, $message_body, @files) = @_; my $msg = MIME::Lite->new( From => $opt->{from}, To => $opt->{to}, Cc => $opt->{cc}, Subject => $subject,

7

Page 8: Perl Maven Cookbook v0.01

Type => 'multipart/mixed' ) or die "Error creating multipart container: $!\n"; $msg->attach( Type => ($message_body =~ /<html>/ ? 'text/html' : 'text/plain'), Data => $message_body ) or die "Error adding the text message part: $!\n"; foreach my $filename (@files) { $msg->attach( Type => ($filename =~ /\.xls$/ ? 'application/xls' : 'text/plain'), Path => $filename, Filename => basename($filename), Disposition => 'attachment' ) or die "Error adding $filename: $!\n"; } if ($opt->{smtp}) { $msg->send('smtp', $opt->{smtp}, Timeout => 60) or die $!; } else { $msg->send or die $!; }

return;}

=head1 SYNOPSIS

Sending and e-mail with or without attachements

perl send_files.pl --from [email protected] [email protected] "Subject line"report.xls --textfile path/to/content.txt--smtp HOSTNAME

=cut

2.6. Read Excel file

examples/applications/read_excel.pl

#!/usr/bin/perl use strict;use warnings;

use Spreadsheet::ParseExcel::Simple qw();my $xls = Spreadsheet::ParseExcel::Simple->read("spreadsheet.xls");

8

Page 9: Perl Maven Cookbook v0.01

foreach my $sheet ($xls->sheets) { while ($sheet->has_data) { my @data = $sheet->next_row; print join "|", @data; print "\n"; }}

2.7. Process file with fixed width records

examples/applications/pack.pl

#!/usr/bin/perluse strict;use warnings; # You need to parse a log file where the fields are fixed length long # and have no delimiters# The definition is as follows:# LABEL: 4 chars# SOURCE: 8 digits# DESTINATION: 8 digits# TYPE: 4 chars# VALUE: 8 digitsmy $file = shift or die "Usage: $0 pack.txt\n";

open(my $data, '<', $file) or die "Could not open '$file'\n";while (my $line = <$data>) { print $line; chomp $line; my ($label, $source, $dest, $type, $value) = unpack ("A4 A8 A8 A4 A8", $line); print "LABEL: $label SOURCE: $source DEST: $dest TYPE: $type VALUE: $value\n";}

examples/applications/pack.txt

XALD37845566974923342XYZ24023984YQRW49327408234028434ERD24448009

2.8. Process file with multiline records

examples/applications/config.txt

device = 234234name = Bigaddress = 115.6.79.8

9

Page 10: Perl Maven Cookbook v0.01

class = B

device = 234224name = Big Blueaddress = 115.6.69.8class = Balias = Foxbox

device = 234235name = Big Green boxaddress = 115.6.79.1class = Gowner = Boss

device = 334235name = Small Yellowaddress = 115.6.79.10class = Y

examples/applications/process_config.pl

#!/usr/bin/perluse strict;use warnings;

=head1 DESCRIPTION

File have sections separated by empty linesEach section has several field = value entries like this:Given a value of the name field print out all the values in this section

device = 234234name = Bigaddress = 115.6.79.8class = B

=cut

if (@ARGV != 2) { die "\n Usage: $0 filename name\n Try: $0 examples/config.txt Big\n\n";}my ($filename, $name) = @ARGV;

open(my $fh, "<", $filename) or die "Could not open '$filename' $!";my %data;while (my $line = <$fh>) { chomp $line; if ($line =~ /^\s*$/ and %data) { if ($data{name} eq $name) { foreach my $k (keys %data) { printf "%-10s = %s\n", $k, $data{$k}; } exit; }

10

Page 11: Perl Maven Cookbook v0.01

%data = (); } else { my ($field, $value) = split /\s*=\s*/, $line; $data{$field} = $value; }}

2.9. Process multi field csv file

examples/applications/fields.csv

Name,ID,Input,OutputBig Venta,12,Left,RightSmall Elevator,7343124,Bottom,TopGiant Ant,423235,Lower floor,Upper floor

examples/applications/process_fields.pl

#!/usr/bin/perluse strict;use warnings;

use Text::CSV_XS qw();use Data::Dumper qw(Dumper);

my $filename = shift or die "Usage: $0 FILENAME\n";open(my $fh, "<", $filename) or die "Could not open '$filename': $!";

my $csv = Text::CSV_XS->new;

my $key = "Name";

my $header = <$fh>;chomp $header;$csv->parse($header);my @header = $csv->fields;

my %data;

while (my $line = <$fh>) { chomp $line; $csv->parse($line); my @cols = $csv->fields; my %h; @h{@header} = @cols;

$data{$h{$key}} = \%h;}

print Dumper \%data;

11

Page 12: Perl Maven Cookbook v0.01

2.10. Fetch web page

examples/applications/get_webpage.pl

#!/usr/bin/perluse strict;use warnings;

use LWP::Simple qw(get);

my $page = get "http://perlmaven.com/";if ($page) { print "Site is alive\n";} else { print "Site is not accessible\n";}

2.11. Generate web page

We are building the HTML pages from a template utilizing the HTML::Template module from CPAN.Besides the plain HTML the template has additional TMPL_* tags that will be filled by the values byHTML::Template.

examples/applications/html.tmpl

<html><head></head><body>

<TMPL_IF echo> You typed <TMPL_VAR echo></TMPL_IF>

<form> <input name="text"> <input type=submit" value="Echo"></form>

</body></html>

This is a simple Perl script that should be installed to a CGIExec enabled directory of Apache. Whenthe user hits this page the first time it displays a white page with only entry-box and a submit button

12

Page 13: Perl Maven Cookbook v0.01

on it. the user can fill the box,

examples/applications/html.pl

#!/usr/bin/perluse strict;use warnings;

use CGI;use HTML::Template;

my $template = HTML::Template->new(filename => "examples/html.tmpl");my $q = CGI->new;print $q->header;

if ($q->param("text")) { my $text = $q->param("text"); $template->param(echo => $text);}print $template->output

2.12. Parse XML file

examples/applications/simple.xml

<people> <person id="1"> <fname>Josef</fname> <lname>Kiss</lname> <idnum>4342324234</idnum> <children> <child> <id>3</id> </child> </children> </person> <person id="2"> <fname>Peter</fname> <lname>Kiss</lname> <idnum>8768996</idnum> </person> <person id="3"> <fname>Zoltan</fname> <lname>Kiss</lname> <idnum>09808760</idnum> </person></people>

examples/applications/xml_simple.pl

13

Page 14: Perl Maven Cookbook v0.01

#!/usr/bin/perluse strict;use warnings;

use XML::Simple qw(XMLin);

my $xml = XMLin("examples/simple.xml", ForceArray => 1);#use Data::Dumper qw(Dumper);#print Dumper $xml;#exit;

print join "-", keys %{$xml->{person}};print "\n";

foreach my $id (keys %{$xml->{person}}) { printf "%-10s %-10s %-10s\n", $xml->{person}{$id}{fname}[0], $xml->{person}{$id}{lname}[0], $xml->{person}{$id}{idnum}[0];}

2.13. Database access using DBI and DBD::SQLite

examples/applications/db_create.pl

#!/usr/bin/perluse strict;use warnings;

use DBI;

my $dbfile = "sample.db";

unlink $dbfile if -e $dbfile;my $sql = <<'SCHEMA';CREATE TABLE people ( id INTEGER PRIMARY KEY, fname VARCHAR(100), lname VARCHAR(100));SCHEMA

my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","", {});$dbh->do($sql);

examples/applications/db.pl

#!/usr/bin/perluse strict;

14

Page 15: Perl Maven Cookbook v0.01

use warnings;

use Getopt::Long qw(GetOptions);use DBI qw();

my $action;GetOptions("action=s" => \$action);if (not $action or $action !~ /^(insert|selecta|selecth)$/) { print <<"USAGE";Usage: $0 --action insert|selecta|selecth

USAGE exit;}my $dbfile = "sample.db";

my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","", {});

if ($action eq "insert") { insert();}if ($action eq "selecta") { fetch_arrays();}if ($action eq "selecth") { fetch_hashref();}

sub insert { my @people = ( ['Foo', 'Bar'], ['Apple', 'Pie'], ); foreach my $person (@people) { $dbh->do("INSERT INTO people (id, fname, lname) VALUES(?, ?, ?)", undef, 1, @$person); } return;}

sub fetch_arrays { my $sth = $dbh->prepare("SELECT lname, fname FROM people WHERE id = ?"); $sth->execute(1); while (my @result = $sth->fetchrow_array()) { print "lname: $result[0], fname: $result[1]\n"; } $sth->finish; return;}

sub fetch_hashref { my $sth = $dbh->prepare("SELECT lname, fname FROM people WHERE id = ?");

15

Page 16: Perl Maven Cookbook v0.01

$sth->execute(1); while (my $result = $sth->fetchrow_hashref("NAME_lc")) { print "lname: $result->{lname}, fname: $result->{fname}\n"; } $sth->finish; return;}

2.14. Net::LDAP

examples/applications/ldap.pl

#!/usr/bin/perluse strict;use warnings;

use Net::LDAP;my $server = "ldap.itd.umich.edu";my $ldap = Net::LDAP->new( $server ) or die $@;$ldap->bind;

my $result = $ldap->search( base => "", filter => "(&(cn=Jame*) (sn=Woodw*))", attr => ["mail"],);

$result->code && die $result->error;

printf "COUNT: %s\n", $result->count;

foreach my $entry ($result->entries) { $entry->dump;}print "===============================================\n";

foreach my $entry ($result->entries) { printf "%s <%s>\n", $entry->get_value("displayName"), ($entry->get_value("mail") || ''); $entry->add ( "nephew" => "Foo Bar" ); $entry->replace ( "mail" => '[email protected]'); my $res = $entry->update($ldap); if ($res->code) { warn "Failed to update: " . $res->error . "\n"; };}

my $res = $ldap->add( 'cn=root, o=University of Michigan, c=US', attr => [

16

Page 17: Perl Maven Cookbook v0.01

cn => 'Foo Bar', ou => 'My Place in the Universe', mail => '[email protected]', ],);if ($res->code) { warn "Failed to add: " . $res->error . "\n";}

$ldap->unbind;

2.15. Tie::File

examples/applications/tie.pl

#!/usr/bin/perluse strict;use warnings;

use Tie::File;

tie my @file, 'Tie::File', "data.txt" or die $!;$file[7] = "Hello";

17

Page 18: Perl Maven Cookbook v0.01

3. Book

3.16. Simple Database access using Perl DBI and SQL

While in most fields Perl adheres to the concept of TMTOWDI,in accessing relation databases Perlhas a de-facto standardcalled DBI or Database independent interface for Perl.

ArchitectureThe Perl scripts use DBI which in turn uses the appropriateDatabase Driver (e.g. DBD::Oracle forOracle , DBD::Pg for PostgreSQL and DBD::SQLite to access SQLite ).Those drivers are compiled together with the C client librariesof the respective database engine. Incase of SQLite, of course all thedatabase engine gets embedded in the perl application.It is very hard to improve on the lovely ASCII-art that comeswith the documentation of DBI so let mereproduce it here: |<- Scope of DBI ->| .-. .--------------. .-------------. .-------. | |---| XYZ Driver |---| XYZ Engine | | Perl | | | `--------------' `-------------' | script| |A| |D| .--------------. .-------------. | using |--|P|--|B|---|Oracle Driver |---|Oracle Engine| | DBI | |I| |I| `--------------' `-------------' | API | | |... |methods| | |... Other drivers `-------' | |... `-'

Simple exampleI'll use SQLite to demonstrate the examples. That will make itvery easy for you to try them on yourcomputer.(e.g All versions of DWIM Perl already comewith the necessary modules.) #!/usr/bin/perl use strict; use warnings; use DBI; my $dbfile = "sample.db"; my $dsn = "dbi:SQLite:dbname=$dbfile"; my $user = ""; my $password = ""; my $dbh = DBI->connect($dsn, $user, $password, { PrintError => 0, RaiseError => 1, AutoCommit => 1, FetchHashKeyName => 'NAME_lc', }); $dbh->disconnect;We load DBI but we do not explicitly load the database driver.That will be done by DBI. The DSN(Data Source Name) is very straight forward.It contains the type of the database. That will be the clueto DBI which DBD to load.In case of SQLite, the only thing we really need is the path to the databasefile.The username and password fields were left empty. I think they are notrelevant at all for SQLite.The last parameter of the connect call is a reference to a hash containingsome attributes I like to set.The DBI->connect call returns a database handle object that usually we store in a variablecalled$dbh.The call to disconnect from the database is optional as itwill automatically be called when the variable

18

Page 19: Perl Maven Cookbook v0.01

$dbh goes outof scope but it having it might be a clear indication that you are done withthedatabase.

CREATE TABLEOf course having a connection is not enough. We need to be able to fetch data from thedatabase orinsert data into the database but for our example to work first weactually need to create the tables ofthe database.In this case we can do this with a single command: my $sql = <<'END_SQL'; CREATE TABLE people ( id INTEGER PRIMARY KEY, fname VARCHAR(100), lname VARCHAR(100), email VARCHAR(100) UNIQUE NOT NULL, password VARCHAR(20) ) END_SQL $dbh->do($sql);The first one is just a here document of an SQL statement to CREATE TABLE.Then we call the domethod of the database handle which will send theSQL statement to the database.

INSERTNow let's see the real thing, inserting data: my $fname = 'Foo'; my $lname = 'Bar', my $email = '[email protected]'; $dbh->do('INSERT INTO people (fname, lname, email) VALUES (?, ?, ?)', undef, $fname, $lname, $email);To insert a row we call the $dbh->do method again but instead of passingthe actual data, we putquestion-marks ? as place-holders.The SQL statement is followed by the word undef.That's actually the place of a hash-referenceprovidingparameters to this specific call, similar to the attributespassed to the connect method but Ithink it is rarely used.That is followed by the actual values that go in place of the the place-holders.As you can see we did not have to put the place-holders in any kind of quotesnor did we have tosomehow convert the values. DBI did it for us.This helps us avoid SQL injection attacks.Even if you meet someone called Bobby Tables .

UPDATEFor updating some data in the database we also use the do method. my $password = 'hush hush'; my $id = 1; $dbh->do('UPDATE people SET password = ? WHERE id = ?', undef, $password, $id);Nothing special here. An SQL statement with some place-holders. undefinstead of the extraattributes and the parameters to be used in place ofthe place-holders.

SELECTThis is by far the most interesting part of the database access. As the SELECTstatement can return alot of rows and a lot of values in each row we cannot usea simple call to the do method.

19

Page 20: Perl Maven Cookbook v0.01

Instead, there are several ways to fetch the data. I'll show here two.For both we have 3 steps:prepare the SQL statement.execute the statement with specific data and fetch the rows.From these, the prepare statement can be shared by - assuming the queriesonly differ in the data wepass to them. We create an SQL statement usingquestion marks (?) as place-holders instead ofactual values.This call returns a statement handle object that we usually save in avariable called $sth.Then we call the execute method of the statement handle passing toit values that should be placedinstead of the place-holders.The third step is the really interesting one.In a while loop we fetch the results, row-by row. For this wecan use several methods:The fetchrow_array method will return the values of the next row in the result setas a list, that we canassign to an array. The order of the elements is as the orderof the fields in the query. (fname, lnamein our case).The fetchrow_hashref method will return a reference to a hash. In the hashthe keys will be the namesof the fields in the database. As different databases mightreturn these names of the fields in differentcases we configured our database handlerto make sure they - the names of the fields - will alwaysconverted to lower case.(That's what the FetchHashKeyName parameter did, when connecting to thedatabase.) my $sql = 'SELECT fname, lname FROM people WHERE id > ? AND id < ?'; my $sth = $dbh->prepare($sql); $sth->execute(1, 10); while (my @row = $sth->fetchrow_array) { print "fname: $row[0] lname: $row[1]\n"; } $sth->execute(12, 17); while (my $row = $sth->fetchrow_hashref) { print "fname: $row->{fname} lname: $row->{lname}\n"; }

ExerciseTake the above snippets of code. Use the first one to set up thedatabase and create a table. Thenuse the second one to inserta few people in the table.Finally use the last example to extract some data from the databaseand print it out.If you have any question, feel free to ask below.

Thanksto sigzero for correcting a bug in the examples!

Subscribe to my mailing listIf you are interested getting updates when I post new articles,please subscribe to my newsletter:

20

Page 21: Perl Maven Cookbook v0.01

Index

* CGI - Generate web page (2.11) (page 12)* csv - Process multi field csv file (2.9) (page 11)* database - Database access using DBI and DBD::SQLite (2.13) (page 14)* DBD - Database access using DBI and DBD::SQLite (2.13) (page 14)* DBD::SQLite - Simple Database access using Perl DBI and SQL (3.16) (page 18)* DBI - Database access using DBI and DBD::SQLite (2.13) (page 14) - Simple Database access using Perl DBI and SQL (3.16) (page 18)* df - Reporting file system diskspace usage (df) (2.2) (page 4)* du - Reporting diskspace usage on the mail server (2.3) (page 4) - A du like script (2.4) (page 6)* Excel - Read Excel file (2.6) (page 8)* GET - Fetch web page (2.10) (page 12)* HTML::Template - Generate web page (2.11) (page 12)* http - Fetch web page (2.10) (page 12)* LDAP - Net::LDAP (2.14) (page 16)* LWP::Simple - Fetch web page (2.10) (page 12)* MIME - Send files by e-mail (2.5) (page 7)* Net::LDAP - Net::LDAP (2.14) (page 16)* SQL - Simple Database access using Perl DBI and SQL (3.16) (page 18)* SQLite - Database access using DBI and DBD::SQLite (2.13) (page 14)* Tie::File - Tie::File (2.15) (page 17)* web - Fetch web page (2.10) (page 12)* XML - Parse XML file (2.12) (page 13)* XML::Simple - Parse XML file (2.12) (page 13)