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 8 docx
Nội dung xem thử
Mô tả chi tiết
298 CHAPTER 9 LIST VARIABLES
As shown in the table’s last row, the Shell uses the special @ index to retrieve all values,
preserve any whitespace within them, and separate them from each other by a space.
As usual, double quotes are also required if further processing of the extracted values
isn’t desired.
With Perl, on the other hand, all values are retrieved by using the array name without an index. The only effect of the double quotes is to separate the values on output
with the contents of the ‘$"’ variable—they’re not needed to suppress further processing of the extracted values, because that doesn’t happen anyway.2
Next, we’ll look at different ways to initialize arrays.
Table 9.2 Syntax for using arrays in the Shell and Perl
Shell Perl a Remarks
Assigning a value n[0]=13 $n[0]=13; In Perl, the $ symbol is always
used with the variable name
when referring to a scalar value.
With the Shell, it’s only used
when retrieving a value.
Retrieving and
displaying a value
echo ${n[0]} print $n[0]; The Shell requires the array name
and index to be enclosed in curly
braces.
Deleting a value unset n[0] delete $n[0]; The Shell deletes the designated
element, but Perl maintains the
element’s slot after marking its
value as undefined.
Assigning multiple
values
n=(13 42) @n=(13, 42);
@n=qw/13 42/;
@n=qw!\ | /!;
The Shell recognizes whitespace
as separators in the parenthesized list of initializers. By default,
Perl requires a comma, and
allows additional whitespace.
With the qwX syntax, only
whitespace separators are recognized between paired occurrences of the X delimiter.b
Retrieving and
displaying all values
echo "${n[@]}" print "@n"; See text for explanation.
a. The examples using print assume the use of Perl’s l invocation option.
b. Examples of the qwX quoting syntax are shown in chapter 12.
2 See http://TeachMePerl.com/DQs_in_shell_vs_perl.html for details on the comparative use of double
quotes in the two languages.
USING ARRAY VARIABLES 299
9.1.1 Initializing arrays with piecemeal
assignments and push
As shown in the top row of table 9.2, you can initialize arrays in piecemeal fashion:
$stooges[2]='Curly';
$stooges[0]='Moe';
$stooges[1]='Larry';
Alternatively, you can use explicit lists on both sides of the assignment operator:
($stooges[2], $stooges[0], $stooges[1])=('Curly', 'Moe', 'Larry');
When it’s acceptable to add new elements to the end of an array, you can avoid managing an array index by using push @arrayname, 'new value'. This technique
is used in the shell_types script, which categorizes Unix accounts into those
having human-usable shells (such as /usr/bin/ksh) or “inhuman” shells (such as
/sbin/shutdown):
$ shell_types | fmt -68 # format to fit on screen
THESE ACCOUNTS USE HUMAN SHELLS: root, bin, daemon, lp, games,
wwwrun, named, nobody, ftp, man, news, uucp, at, tim, yeshe, info,
contix, linux, spug, mailman, snort, stu01
THESE ACCOUNTS USE INHUMAN SHELLS: mail, sshd, postfix, ntp, vscan
Because the listing of “human” account names produces a very long line, the Unix
fmt command is used to reformat the text to fit within the width of the screen.
The script’s shebang line (see listing 9.1) arranges for input lines to be automatically split into fields on the basis of individual colons, because that’s the field separator used in the /etc/passwd file, which associates shells with user accounts.
The matching operator on Line 8 checks the last field of each line for the pattern
characteristic of “human” shells and stores the associated account names in @human
using push. Alternatively, Line 12 arranges for the names of the accounts that fail the
test to be stored in @inhuman.
1 #! /usr/bin/perl -wnlaF':'
2
3 BEGIN {
4 @ARGV=( '/etc/passwd' ); # Specify input file
5 }
6
7 # Separate users of "human" oriented shells from others
8 if ( $F[-1] =~ /sh$/ ) {
9 push @human, $F[0];
10 }
11 else {
12 push @inhuman, $F[0];
13 }
Listing 9.1 The shell_types script
300 CHAPTER 9 LIST VARIABLES
14 END {
15 $"=', ';
16 print "\UThese accounts use human shells: \E\n@human\n";
17 print "\UThese accounts use inhuman shells:\E\n@inhuman";
18 }
To make the output more presentable, Line 15 sets the ‘$"’ variable to a comma-space
sequence, and \U is used to convert the output headings to uppercase.
In programs like this, where you don’t care what position a data element is allocated in the array, it’s more convenient to push them onto the array’s end than to
manage an index. In other cases, it may be more appropriate to do piecemeal arrayinitializations using indexing (see, e.g., section 10.5), to maintain control over where
an element is stored.
Next, we’ll look at the syntax and rules for using more advanced indexing
techniques.
9.1.2 Understanding advanced array indexing
Table 9.3 shows the association between array values and indices of both the positive
and negative varieties, both of which are usable in Perl. Negative indexing counts
backward from the end of the array and is most commonly used to access an array’s
last element. Another way to do that is by using an array’s maximum index variable,
whose name is $#arrayname.
Table 9.3 Syntax for advanced array indexing
Initialization @X=('A', 'B', 'C', 'D');
Stored value A B C D
Ordinal Position 1 2 3 4
Positive indexing $X[ 0] $X[ 1] $X[ 2] $X[ 3]
Negative indexing $X[-4] $X[-3] $X[-2] $X[-1]
Indexing with maximum-index variable $X[$#X]
Result A B C D
Slice indexing @X[2,3] "@X[2,0..1]" @X[3,0..2]
Result CD C A B DABC
USING ARRAY VARIABLES 301
As an alternative to repeatedly indexing into an array to access several values, Perl
allows a collection of values—called an array slice3—to be addressed in one indexing
expression (as shown in the table’s bottom panel). You do this by arranging the
comma-separated indices within square brackets in the order desired for retrieval (or
assignment) and putting @arrayname before that expression. The @ symbol is used
rather than $, because multiple indices extract a list of values, not a single scalar value.
You can also specify a range of consecutive indices by placing the range operator
(..) between the end points, allowing the use of 3..5, for instance, as a shortcut for
3, 4, 5.
The following Perl command retrieves multiple values from an array using a slice:
$ cat newage_contacts # field number exceeds index by 1
(510) 246-7890 [email protected]
(225) 424-4242 [email protected]
(928) 312-5789 [email protected]
1/0 2/1 3/2
$ perl -wnla -e 'print "@F[2,0,1]";' newage_contacts
[email protected] (510) 246-7890
[email protected] (225) 424-4242
[email protected] (928) 312-5789
We could have written the Perl command without using an array slice, by typing
print "$F[2] $F[0] $F[1]" in place of print "@F[2,0,1]". But that involves
a lot of extra typing, so it’s not Lazy enough!
Because each array slice is itself a list, you can set the ‘$"’ formatting variable to
insert a custom separator between the list elements:
$ perl -wnla -e '$"=":\t"; print "@F[0,2]";' newage_contacts
(510): [email protected]
(225): [email protected]
(928): [email protected]
We’ll continue with this theme of finding friendlier ways to write array-indexing
expressions in the next section, where you’ll see how a script that lets the user think
like a human makes access to fields a lot easier.
9.1.3 Extracting fields in a friendlier fashion
Sooner or later, every Perl programmer makes the mistake of attempting to use 1 as the
index to extract the first value from an array—rather than 0—because humans naturally count from 1. But with a little creative coding, you can indulge this tendency.
3 The indexed elements needn’t be adjacent, and subsequent slices needn’t run parallel to earlier ones (as
with bread slices), so a better name for this feature might be an index group.
Field numbers / indices
302 CHAPTER 9 LIST VARIABLES
As a case in point, the show_fields2 script allows the user to select fields for display using human-oriented numbers, which start from 1:
$ cat zappa_floyd
Weasels Ripped my Flesh Frank Zappa
Dark Side of the Moon Pink Floyd
$ show_fields2 '1' zappa_floyd # 1 means first field
Weasels
Dark
It works by using unshift (introduced in table 8.2) to prepend a new value to the
array, which shifts the existing values rightward. As a result, the value originally stored
under the index of N gets moved to N+1.
As depicted in Figure 9.1, if 0 was the original index for the value A, after
unshift prepends one new item, A would then be found under 1.
The show_fields2 script also supports index ranges and array slices:
$ cat zappa_floyd # field numbers added
Weasels Ripped my Flesh Frank Zappa
1 2 3 4 5 6
Dark Side of the Moon Pink Floyd
1 2 3 4 5 6 7
$ cat zappa_floyd | show_fields2 '2..4,1' # indices 1..3,0
Ripped my Flesh Weasels
Side of the Dark
It even issues a warning if the user attempts to access (the illegitimate) field 0:
$ show_fields2 '0' zappa_floyd # WRONG!
Usage: show_fields2 '2,1,4..7, etc.' [ file1 ... ]
There's no field #0! The first is #1.
The show_fields2 script, which uses several advanced array-handling techniques,
is shown in listing 9.2.
Line 7 pulls the argument containing the field specifications out of @ARGV and
saves it in the $fields variable. Then, a matching operator is used to ask whether
Figure 9.1 Effect of unshift
Field numbers