Cover | Table of Contents
while, if, for, and foreachgrep, map, sort, and printopen, file reading, and -X (file tests)print. We give it one or more arguments, and
it puts them together for us.print 'Two castaways are ', 'Gilligan', ' and ', 'Skipper', "\n";
sort operator puts its input list in order. In
their theme song, the castaways don't come in alphabetical order, but
sort can fix that for us.my @castaways = sort qw(Gilligan Skipper Ginger Professor Mary-Ann);
reverse operator returns a
list in the opposite order.my @castaways = reverse qw(Gilligan Skipper Ginger Professor Mary-Ann);
grep operator
takes a list of values and a "testing expression." It takes one item
after another in the list and places it into the $_ variable. It then evaluates the testing
expression in a scalar context. If the expression evaluates to a true
value, grep passes $_ on to the output list.my @lunch_choices = grep &is_edible($_), @gilligans_posessions.
grep
operator returns a list of all such selected items. In a scalar
context, grep returns the number of
selected items.my @results = grep EXPR, @input_list; my $count = grep EXPR, @input_list;
$_
(explicitly or implicitly). For example, to find all the numbers
greater than 10, in our print. We give it one or more arguments, and
it puts them together for us.print 'Two castaways are ', 'Gilligan', ' and ', 'Skipper', "\n";
sort operator puts its input list in order. In
their theme song, the castaways don't come in alphabetical order, but
sort can fix that for us.my @castaways = sort qw(Gilligan Skipper Ginger Professor Mary-Ann);
reverse operator returns a
list in the opposite order.my @castaways = reverse qw(Gilligan Skipper Ginger Professor Mary-Ann);
grep operator
takes a list of values and a "testing expression." It takes one item
after another in the list and places it into the $_ variable. It then evaluates the testing
expression in a scalar context. If the expression evaluates to a true
value, grep passes $_ on to the output list.my @lunch_choices = grep &is_edible($_), @gilligans_posessions.
grep
operator returns a list of all such selected items. In a scalar
context, grep returns the number of
selected items.my @results = grep EXPR, @input_list; my $count = grep EXPR, @input_list;
$_
(explicitly or implicitly). For example, to find all the numbers
greater than 10, in our grep
expression we check if $_ is
greater than 10.my @input_numbers = (1, 2, 4, 8, 16, 32, 64); my @bigger_than_10 = grep $_ > 10, @input_numbers;
$_. Here's an example
of an implicit reference to $_ from
the pattern match operator:my @end_in_4 = grep /4$/, @input_numbers;
my $average = $total / $count; # divide by zero? print "okay\n" unless /$match/; # illegal pattern? open MINNOW, '>ship.txt' or die "Can't create 'ship.txt': $!"; # user-defined die? &implement($_) foreach @rescue_scheme; # die inside sub?
eval operator as its
error-trapping mechanism.eval { $average = $total / $count } ;eval block, the block is done executing. But
even though the code inside the block is finished, Perl continues
running the code just after the eval.
It's most common after an eval to
immediately check $@, which will
either be empty (meaning that there was no error) or the dying words
Perl had from the code that failed, perhaps something like "divide by zero" or a longer error
message.eval { $average = $total / $count } ;
print "Continuing after error: $@" if $@;
eval { &rescue_scheme_42 } ;
print "Continuing after error: $@" if $@;eval block because eval is a function (not a control structure,
such as if or while). But the block is a true block and may
include lexical variables ("my"
variables) and any other arbitrary statements. As a function, eval has a return value much like a
subroutine's (the last expression evaluated, or a value returned early
by the return keyword). Of course, if
the code in the block fails, no value is returned; this gives undef in a scalar context, or an empty list in
a list context. Thus, another way to calculate an average safely looks
like this:my $average = eval { $total / $count } ;$average is either the
quotient or undef, depending upon
whether the operation completed successfully or not.eval
blocks. The power of an eval, whose parameter is a string expression
instead of a block. It compiles and executes code from a string at
runtime. While this is useful and supported, it is also dangerous if any
untrustworthy data has gotten into the string. With a few notable
exceptions, we recommend you avoid eval on a string. We'll use it a bit later,
and you might see it in other people's code, so we'll show you how it
works anyway.eval '$sum = 2 + 2'; print "The sum is $sum\n";
eval is the
last evaluated expression, so we really don't need the entire statement
inside the eval.#!/usr/bin/perl
foreach my $operator ( qw(+ - * /) ) {
my $result = eval "2 $operator 2";
print "2 $operator 2 is $result\n";
}+ - *
/ and use each of those inside our eval code. In the string we give to eval, we interpolate the value of $operator into the string. The eval executes the code that the string
represents and returns the last evaluated expression, which we assign it
to $result.eval can't properly compile
and run the Perl code we hand it, it sets $@ just like in its block form. In this
example, we want to trap any divide-by-zero errors, but we don't divide
by anything (another sort of error).print 'The quotient is ', eval '5 /', "\n"; warn $@ if $@;
eval catches the syntax
error and puts the message in $@,
which we check immediately after calling eval.The quotient is syntax error at (eval 1) line 2, at EOF
eval. If you can find another way to do what
you need, try that first. We'll use it later, in Chapter 10 to load code from an
external file, but then we'll also show you a much better way to do that
too.grep to select the
ones whose size in bytes is less than 1000. Use map to transform the strings in this list,
putting four space characters in front of each and a newline character
after. Print the resulting list."/etc" or
'C:\\Windows') whose names match
the pattern. Repeat this until the user enters an empty string instead
of a pattern. The user should not type the forward slashes that are
traditionally used to delimit pattern matches in Perl; the input
pattern is delimited by the trailing newline. Ensure that a faulty
pattern, such as one with unbalanced parentheses, doesn't crash the
program.perldoc command. We give it the
module name we're interested in, and it prints out its
documentation.$ perldoc File::Basename
NAME
fileparse - split a pathname into pieces
basename - extract just the filename from a path
dirname - extract just the directory from a path
SYNOPSIS
use File::Basename;
($name,$path,$suffix) = fileparse($fullname,@suffixlist)
fileparse_set_fstype($os_string);
$basename = basename($fullname,@suffixlist);
$dirname = dirname($fullname);perldoc command. We give it the
module name we're interested in, and it prints out its
documentation.$ perldoc File::Basename
NAME
fileparse - split a pathname into pieces
basename - extract just the filename from a path
dirname - extract just the directory from a path
SYNOPSIS
use File::Basename;
($name,$path,$suffix) = fileparse($fullname,@suffixlist)
fileparse_set_fstype($os_string);
$basename = basename($fullname,@suffixlist);
$dirname = dirname($fullname);use. We're not going to go into all of the
details here, but we'll get to those in Chapters 10 and 15. At the moment, we just want
to use the module. Let's start with File::Basename, that same module from the core
distribution. To load it into our script, we say:use File::Basename;
File::Basename
introduces three subroutines, fileparse, basename, and dirname, into our script. From this point forward, we can say:my $basename = basename( $some_full_path ); my $dirname = dirname( $some_full_path );
basename and dirname subroutines ourselves, or (nearly) as
if they were built-in Perl functions. These routines pick out the
filename and the directory parts of a pathname. For example, if $some_full_path were D:\Projects\Island Rescue\plan7.rtf
(presumably, the program is running on a Windows machine), then $basename would be plan 7.rtf and the $dirname would be D:\Projects\Island Rescue.File::Basename module knows
what sort of system it's on, and thus its functions figure out how to
correctly parse the strings for the different delimiters we might
encounter.dirname subroutine. We've now overwritten it
with the definition provided by File::Basename! If we had turned on warnings,
we would have seen a message stating that; but otherwise, Perl really
doesn't care.use operation to limit its actions by
specifying a list of subroutine names following the module name, called
the import list:use File::Basename ('fileparse', 'basename');dirname alone. Of course, this is
awkward to type, so more often we'll see this written with the
quotewords operator:use File::Basename qw( fileparse basename );
qw( ) list for consistency and
maintenance; often we'll go back to say "give me another one from here,"
and it's simpler if it's already a qw(
) list.dirname routine, but what if we still want the
functionality provided by File::Basename's dirname? No problem. We just spell it out with
its full package specification:my $dirname = File::Basename::dirname($some_path);
use
doesn't change which subroutines are defined in the module's package (in
this case, File::Basename). We can
always use the full name regardless of the import list, as in:my $basename = File::Basename::basename($some_path);
use File::Basename ( ); # no import my $base = File::Basename::basename($some_path);
File::Basename with what another core module
has by looking at File::Spec. The
File::Spec module is designed to
support operations commonly performed on file specifications. (A file
specification is usually a file or directory name, but it may be a name
of a file that doesn't exist—in which case, it's not really a filename,
is it?)File::Basename
module, the File::Spec module has a
primarily objectoriented interface. We load the module with use, as we did before.use File::Spec;
catfile method joins a
list of strings with the appropriate directory separator:my $filespec = File::Spec->catfile( $homedir{gilligan},
'web_docs', 'photos', 'USS_Minnow.gif' );catfile of the File::Spec class, which builds a path
appropriate for the local operating system and returns a single
string. This is similar in syntax to the nearly two dozen other
operations provided by File::Spec.File::Spec module provides
several other methods for dealing with file paths in a portable manner.
You can read more about portability issues in the
perlport documentation.File::Spec module seems since it doesn't have
objects, let's look at yet another core module, Math::BigInt, which can handle integers beyond
Perl's native reach.use Math::BigInt; my $value = Math::BigInt->new(2); # start with 2 $value->bpow(1000); # take 2**1000 print $value->bstr( ), "\n"; # print it out
new, against
the class name to create instances, and then calls instance methods,
such as bpow and bstr, against those instances.Data::Dumper output for the detailed
module index. Of course, these indices are all derived automatically
from databases at the master server using other Perl programs. Often,
the mirroring of the CPAN from one server to another is done with a
now-ancient Perl program called mirror.pl.wget here, but it doesn't matter which tool
you use.$ wget http://www.cpan.org/.../HTTP-Cookies-Safari-1.10.tar.gz $ tar -xzf HTTP-Cookies-Safari-1.10.tar.gz $ cd HTTP-Cookies-Safari-1.10s
Makefile.PL, we run this
series of commands to build, test, and finally install the
source:$ perl Makefile.PL $ make $ make test $ make install
PREFIX argument:$ perl Makefile.PL PREFIX=/Users/home/Ginger
PERL5LIB environment variable. Perl
adds those directories to its module directory search list.$ export PERL5LIB=/Users/home/Ginger
lib pragma
to add to the module search path, although this is not as friendly,
since we have to change the code, but also because it might not be the
same directory on other machines where we want to run the code.#!/usr/bin/perl use lib qw(/Users/home/Ginger);
Build.PL file instead of a Makefile.PL, the process is the same. These
distributions use Module::Build to
build and install code. Since Module::Build is not a core Perl
module, we have to install it before we can install the
distribution that needs it.$ perl Build.PL $ perl Build $ perl Build test $ perl Build install
Module::Build, we add the —install_base parameter. We tell Perl how to
find modules the same way we did before.$ perl Build.PL --install_base /Users/home/Ginger
Makefile.PL and Build.PL in a distribution. What do we do
then? We can use either one. Play favorites, if you like.@INC. The
use statement executes at compile
time, so it looks at the module search path, @INC, at compile time. That can break our
program in hard-to-understand ways unless we take @INC into consideration./home/gilligan/lib, and we place our own
Navigation::SeatOfPants module in
/home/gilligan/lib/Navigation/SeatOfPants.pm.
When we load our module, Perl won't find it.use Navigation::SeatOfPants;
@INC and shows us all of the directories it
has in that array.Can't locate Navigation/SeatofPants.pm in @INC (@INC contains: ...)
@INC before we call the use. However, even adding:unshift @INC, '/home/gilligan/lib'; # broken use Navigation::SeatOfPants;
unshift happens at runtime, long after the
use was attempted at compile time.
The two statements are lexically adjacent but not temporally adjacent.
Just because we wrote them next to each other doesn't mean they execute
in that order. We want to change @INC
before the use executes. One way to
fix this is to add a BEGIN block
around the push:BEGIN { unshift @INC, '/home/gilligan/lib'; }
use Navigation::SeatOfPants;use.use lib '/home/gilligan/lib'; use Navigation::SeatOfPants;
lib pragma takes one or more arguments and adds them at the
beginning of the @INC array, just
like unshift did before. It works because it executes at compile time, not runtime.
Hence, it's ready in time for the File::Spec and Cwd modules, both of which come with Perl,
should help. Print each path with four spaces before it and a newline
after it, just like you did for Exercise 1 of Chapter 2. Can you reuse part
of that answer for this problem?Return to Intermediate Perl