Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Minimal Perl For UNIX and Linux People 9 potx
Nội dung xem thử
Mô tả chi tiết
356 CHAPTER 10 LOOPING FACILITIES
From a Perlish perspective, you can think of select as a special kind of interactive
variation on a foreach loop. But rather than having each list-value assigned automatically to the loop variable for one iteration, select only assigns values as they are
selected by the user.
Next, you’ll see how you can avoid “re-inventing wheels” by using this loop.
10.7.1 Avoiding the re-invention of the
“choose-from-a-menu” wheel
Although Perl has no counterpart to the Shell’s handy select loop, its functionality
is provided by a CPAN module called Shell::POSIX::Select.
21 It provides its
services through source-code filtering, which means it extracts the select loops from
your program and rewrites them using native Perl features. As a result, you can use a
feature that’s missing from Perl as if it were there!
The benefit of bringing the select loop to Perl is that it obviates the need for terminal applications to provide their own implementations of the choose-from-a-menu
code, which indulges the programmer’s noble craving for Laziness—and thereby
increases productivity.
Table 10.9 shows the syntax variations for the Shell’s version of the select loop.
If in LIST is omitted (as in Form 0), in "$@" is used by default to provide automatic
processing of the script’s (or function’s) argument list.
Some of the major forms of Perl’s select loop are shown in table 10.10. These
take their inspiration from the Shell and then add enhancements for greater friendliness and, well, Perlishness.
As you can see, Perl’s select lets you omit any or even all of its components (apart
from the punctuation symbols). For example, if the loop variable is omitted, as in
Forms 0, 1, and 2, $_ is used by default. If the LIST is omitted, as in Forms 0 and 1,
the appropriate arguments are used by default (i.e., those provided to the script or the
21 Written by yours truly, a long-time Shell programmer turned Perl proponent, while writing this chapter—so I wouldn't have to say “the best Shell loop is missing from Perl”.
Table 10.9 The Shell’s select loop
select var ; do commands; done # Form 0
select var in LIST; do commands; done # Form 1
Table 10.10 The select loop for Perl
use Shell::POSIX::Select;
select () { } # Form 0
select () { CODE; } # Form 1
select (LIST) { CODE; } # Form 2
select $var (LIST) { CODE; } # Form 3
THE CPAN’S select LOOP FOR PERL 357
enclosing subroutine), as with its Shell counterpart. And if CODE is omitted (as in
Form 0), a statement that prints the loop variable is used as the default code block.
Because system administrators have the responsibility for monitoring user activity
on their systems, they might find the following application of select to be of particular interest.
10.7.2 Monitoring user activity: the show_user script
This program allows the user to obtain a system-activity report for users who are currently logged in:
$ cat show_user
#! /usr/bin/perl –wl
use Shell::POSIX::Select;
# Get list of who's logged in
@users=`who | perl -wnla -e ' print \$F[0]; ' | sort -u`;
chomp @users; # remove newlines
# Let program's user select Unix user to monitor
select ( @users ) { system "w $_"; }
This script uses the who command to get the list of current users, and then a separate
Perl command to isolate their names from the first column of that report. Note the
need to backslash the $ to prevent the Perl script from providing its own (null) value
for $F[0] before the who | perl | sort pipeline is launched. sort is used with the
“unique lines” option to remove duplicate user names for those logged in more than
once. The w command, which reports the selected user’s activity, won’t appreciate
finding newlines attached to the ends of those names, so the @users array is chomp’d
to remove them.
Here’s a sample run of the script:
$ show_user
1) phroot 2) tim
Enter number of choice: 2
3:51pm up 4 days, 17:57, 7 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
tim pts/1 lumpy Mon10am 3days 18.91s 1.19s -bash
tim pts/3 stumpy Mon10am 28:16m 0.48s 0.48s bash -login
tim tty5 grumpy Sun 3pm 28:16m 1.71s 1.04s slogin lumpy
tim pts/0 bumpy Sun 4pm 1.00s 4.03s 0.14s w tim
<ENTER>
1) phroot 2) tim
Enter number of choice: <^D>
358 CHAPTER 10 LOOPING FACILITIES
Note that the user pressed <ENTER> to redisplay the menu and <^D> to exit the loop,
just as she’d do with the Shell’s select.
22
Next, you’ll see how select can facilitate access to Perl’s huge collection of
online man pages.
10.7.3 Browsing man pages: the perlman script
One of the obstacles faced by all Perl programmers is determining which one of Perl’s
more than 130 cryptically named man pages covers a particular subject. To make this
task easier, I wrote a script that provides a menu interface to Perl’s online documentation.
Figure 10.1 shows the use of perlman, which lets the user choose a man page
from its description. For simplicity’s sake, only a few of Perl’s man pages are listed in
the figure, and only the initial lines of the selected page are displayed.23
22 For those who don’t like that behavior (including me), there’s an option that causes the menu to be
automatically redisplayed before each prompt. I wish the Shell’s select also had that feature!
23 The select loop is a good example of the benefits of Perl’s source-code filtering facility, which is described in the selected man page, perlfilter.
Figure 10.1 Demonstration of the perlman script
THE CPAN’S select LOOP FOR PERL 359
Before we delve into the script’s coding, let’s discuss what it does on a conceptual level.
The first thing to understand is that man perl doesn’t produce “the” definitive
man page on all things Perlish. On the contrary, its main purpose is to act as a table
of contents for Perl’s other man pages, which deal with specific topics.
Toward this end, man perl provides a listing in which each man page’s name is
paired with a short description of its subject, in this format:
perlsyn Perl syntax
As illustrated in the figure, the role of perlman is to let the user select a man-page
name for viewing from its short description.
Listing 10.7 shows the script. Because it’s important to understand which of its
elements refer to the man-page names versus their corresponding descriptions, distinctive highlighting with bold type (for man-page names) and underlined type (for
descriptions) is used.
1 #! /usr/bin/perl -w
2
3 use Shell::POSIX::Select;
4
5 $perlpage=`man perl`; # put name/description records into var
6
7 # Man-page name & description have this format in $perlpage:
8 # perlsyn Perl syntax
9
10 # Loop creates hash that maps man-page descriptions to names
11 while ( $perlpage =~ /^\s+(perl\w+)\s+(.+)$/mg ) { # get match
12
13 # Load ()-parts of regex, from $1 and $2, into hash
14 $desc2page{$2}=$1; # e.g., $hash{'Perl syntax'}='perlsyn'
15 }
16
17 select $page ( sort keys %desc2page ) { # display descriptions
18 system "man $desc2page{$page}"; # display requested page
19 }
The script begins by storing the output of man perl in $perlpage on Line 5. Then
a matching operator, as the controlling condition of a while loop (Line 11), is used
to find the first man-page name (using “perl\w+”) and its associated description
(using “.+”) in $perlpage. The m modifier on the matching operator allows the
pattern’s leading ^ to match the beginning, and its $ the end, of any of the lines
within the variable (see table 3.6 on multi-line mode).
Capturing parentheses (see table 3.8) are used in the regex (Line 11) to store
what the patterns matched in the special variables $1 and $2 (referring to the first
Listing 10.7 The perlman script
360 CHAPTER 10 LOOPING FACILITIES
and second set of parentheses, respectively), so that in Line 14 the man-page name
can be stored in the %desc2page hash, using its associated description as the key.
The next iteration of the loop will look for another match after the end of the previous one, due to the use of the matching operator’s g modifier in the scalar context
of while’s condition.24
Finally, in Lines 17–19, select displays the numbered list of sorted man-page
descriptions in the form “7) Perl source filters”. Then it obtains the user’s selection,
retrieves its corresponding page name from the hash, and invokes man to display the
requested page (in the case of figure 10.1, “perlfilter”).
As you might imagine, this script is very popular with the students in our classes,
because it lets them find the documentation they need without first memorizing lots
of inscrutable man-page names (such as “perlcheat”, “perltoot”, and “perlguts”).
TIP You can use the only Shell loop that Larry left out of Perl by getting the
Shell::POSIX::Select module from the CPAN.
10.8 SUMMARY
Perl provides a rich collection of looping facilities, adapted from the Bourne shell, the
C shell, and the C language.
The closely-related while and until loops continue iterating until the controlling condition becomes False or True, respectively. You saw while used to incrementally compress images until a target size was reached (in compress_image, section
10.2.2) and to extract and print key/value pairs from a hash with the assistance of the
each function (in show_pvars, section 10.2.3).
Perl also provides bottom-tested loops called do while and do until, which
perform one iteration before first testing the condition. Although these aren’t “real”
loops, the savvy programmer can construct functional replacements using while and
until with continue blocks to allow loop-control directives to function properly
(as shown in confirmation, section 10.6.4).
The foreach loop provides the easiest method for processing a list of values,
because it frees you from the burden of managing indices. You saw it used to remove
files (rm_files, section 10.4.1) and to perform text substitutions for deciphering
acronyms in email messages (expand_acronyms, section 10.4.4).
The relatively complex for loop should be used in cases where iteration can be controlled by a condition, and which benefit from its index-management services. An example is the raffle script (section 10.5.1), which needs to process its arguments in pairs.
24 The meaning of the matching operator’s g modifier is context dependent—in list context, it causes all
the matches (or else the captured sub-matches, if any) to be returned at once. But in scalar context, the
matches are returned one at a time.