10.3 Perl

While the Bourne shell has many strengths, some things it is not particularly good at are manipulating text and dealing with lists and other complicated data structures. A programmer needing to manipulate text from a Bourne shell script usually calls other programs like sed and awk . But this can quickly become cumbersome. That's when many programmers turn to Perl. Perl is the ultimate language for text manipulation, and it has powerful tools for manipulation of lists and other data structures.

10.3.1 Basics of Perl

Using the Bourne shell, you can simply list Unix commands and they will be executed, unless the word you use happens to be one of the few reserved keywords like if or while . In Perl, this is not the case. Perl relies less on outside Unix commands, and as a result, it expects you to use Perl syntax by default. For example, instead of using the Unix echo command to print text to the screen, you will use Perl's print function:

 
 #!/usr/bin/perl print "Hello world\n"; 

Perl is often installed as /usr/bin/perl , but if it is installed elsewhere on your system, be sure to modify the #! line appropriately.

Notice that the line ends with a semicolon. Every line in a Perl program must end with a semicolon; it is not optional as it is in the Bourne shell. [4] Also notice that at the end of the print function, a newline is specified with \n . Unlike the Unix echo command, the Perl print function does not print a newline at the end by default.

[4] The term "line" here doesn't really mean a line of text. It would be more accurate to say that every command must end with a semicolon. A command can span multiple lines and the semicolon will be only at the end of the last line.

10.3.2 Using Variables

One major difference between Perl and the Bourne shell is that in Perl, variable names are always preceded by a dollar sign, whether they are being set or read. For example:

 
 #!/usr/bin/perl $a=foobar; print "$a\n"; 

10.3.3 Local and Environment Variables

All variables in Perl are local to Perl. If you wish to access an environment variable, you can do it this way:

 
 #!/usr/bin/perl print "$ENV{HOME}\n"; 

This prints the value of the environment variable HOME. You can set it similarly:

 
 $ENV{HOME}="/var/tmp/foobar"; 

The ENV variable here is really a special kind of data structure called a hash, which is described in more detail below.

10.3.4 Conditionals

Conditionals in Perl are similar to those C, except that the "else if" syntax is neither the else if used in C nor the elif used in the Bourne shell. Instead it is elsif :

 
 #!/usr/bin/perl $a=green; if ($a eq "red") { print "Found red\n"; } elsif ($a eq "green") { print "Found green\n"; } else { print "Found a color other than red or green\n"; } 

As you can see, strings in Perl are compared with the eq operator. Integer comparisons are as:

 
 #!/usr/bin/perl $a=75 if ($a == 0); then print "Zero\n"; } elsif ($a <= 50) { print "Less than or equal to 50\n"; } elsif ($a < 80) { print "Less than 80\n"; } elsif ($a >= 80) { print "Greater than or equal to 80\n"; } 

Perl can also perform tests on files:

 
 #!/usr/bin/perl if (-r "/etc/passwd") { print "Readable\n"; } else { print "Not readable\n"; } 

The full list of tests is available in the Alphabetical Listing of Perl Functions section of the perlfunc man page.

The syntax for the and and or operators is && and , respectively:

 
 #!/usr/bin/perl if ( (12>5) && (3<2) ) { print "I bet this won't happen.\n"; } if ( (12>5)  (3<2) ) { print "I bet this will.\n"; } 

10.3.5 Text Manipulation

An in-depth discussion of the text manipulation capabilities of Perl is outside the scope of this book, but a sampling of the basic features gives you a good starting point. Perl uses regular expressions in a similar manner to sed and awk . The Perl operator for performing regular expression functions is =~ (an equal sign followed by a tilde). For example:

 
 #!/usr/bin/perl $a="foobar"; if ($a=~/oob/) { print "Contains oob\n"; } else { print "Does not contain oob\n"; } 

The expression $a=~/oob/ evaluates true when the string "oob" is present within the text of $a . It is also possible to replace text using s/text/replacement/ syntax:

 
 #!/usr/bin/perl $a="foobar"; $a=~s/oo/abcde/; print $a."\n"; 

The result of running this program is:

 
 Solaris% ./test.pl fabcdebar 

This program also demonstrates another useful tool of text manipulation: Placing a period between two strings concatenates them. The print statement on the last line prints $a followed by an appended newline ( \n ).

Details on the many regular expression options available in Perl can be found in the perlre man page. Additionally, the perlfunc man page lists many Perl functions that can manipulate text. For example, the chop function removes the last character from a string:

 
 #!/usr/bin/perl $a="foobar"; chop $a; print $a."\n"; 

The result is:

 
 Solaris% ./test.pl fooba 

This is a handy function when you are reading lines from a file or from the standard input. You can use chop to remove the newline present at the end of each line.

10.3.6 Lists

Most shell scripting languages have little to no support for manipulating lists, but Perl has excellent functionality for this. A list in Perl is a variable like any other, except that it is preceded by an at sign instead of a dollar sign. Here is an example of initializing and using a list:

 
 #!/usr/bin/perl @dances=("Waltz", "Foxtrot", "Tango", "Quickstep"); print "The first dance in the list is $dances[0]\n"; print "The entire list is:\n"; foreach $i (@dances) { print " $i\n"; } 

Note that when you refer to the variable dances in a place where a list is expected ( list context ), it is called @dances , but when it is referenced in a place where a normal variable is expected ( scalar context ), $dances is used.

Perl has several functions for manipulating lists. The push function appends a value to the end of a list, while the pop function removes a value from the end:

 
 #!/usr/bin/perl @dances=("Waltz", "Foxtrot", "Tango", "Quickstep"); push(@dances, "Viennese Waltz"); $a=pop(@dances); print "The last dance is $a\n"; $a=pop(@dances); print "The last dance is $a\n"; 

This script produces:

 
 Solaris% /var/tmp/test.pl The last dance is Viennese Waltz The last dance is Quickstep 

The shift function removes a value from the beginning of the list, and the unshift function prepends a value onto the beginning of the list:

 
 #!/usr/bin/perl @dances=("Waltz", "Foxtrot", "Tango", "Quickstep"); unshift(@dances, "Samba"); $a=shift(@dances); print "The first dance is $a\n"; $a=shift(@dances); print "The first dance is $a\n"; 

when you run this:

 
 Solaris% ./test.pl The first dance is Samba The first dance is Waltz 

The shift function is often used in parsing command line arguments, as demonstrated later.

One final trick that is useful to know: The variable $#dances will contain the index of the last element in the list dances . That is, it will be one less than the size of the list. The following code is another way to print the list of dances:

 
 #!/usr/bin/perl @dances=("Waltz", "Foxtrot", "Tango", "Quickstep"); for $i (0 .. $#dances) { print "$dances[$i]\n"; } 

10.3.7 Hashes

Hashes are another useful data structure in Perl. A hash is a set of key/value pairs. For example, the environment variables passed to a Perl program are stored in a hash called ENV . The name of an environment variable in ENV is the key part of the key/value pair, and the environment variable's value is the value part of the pair.

Much as you denote a variable representing an entire list by preceding it with an at sign instead of a dollar sign, you begin a variable representing an entire hash with a percentage sign. The ENV hash is then %ENV . But just as with lists, when you refer to an element of a hash in a scalar context, use a dollar sign instead. The syntax for accessing an element of a hash uses braces:

 
 #!/usr/bin/perl $vendor{"switch1"}="cisco"; $vendor{"switch2"}="enterasys"; print "The vendor for switch1 is " . $vendor{"switch1"} . "\n"; 

And the familiar example for accessing and changing environment variables is:

 
 #!/usr/bin/perl print "$ENV{HOME}\n"; $ENV{HOME}="/var/tmp/foobar"; 

10.3.8 Reading from a File

Reading lines from a file is easy in Perl:

 
 #!/usr/bin/perl open (FILE, "/etc/passwd"); while (<FILE>) { print $_; } close(FILE); 

This will print every line from the password file. The variable $_ is special; it is set to successive lines of the file each time through the loop. Note that $_ will include the newline character at the end of each line. If you wish to remove the final newline character, you can use the chop function described in Section 10.3.5. In general, the $_ variable in Perl refers to whatever the "current thing" is. In this case, it is lines from the file.

Of course, it would be better programming practice to check if the file can actually be opened before you try to read from it, and you can do this in a variety of ways. The following will exit the script and print an error message if the file cannot be opened:

 
 #!/bin/sh open(FILE, "/tmp/myfile")  die "Could not open file"; while (<FILE>) { print $_; } close(FILE); 

If you wish to read from the standard input, you can skip the open and close lines and use an empty file handle:

 
 #!/usr/bin/perl while (<>) { print $_; } 

10.3.9 Writing to a File

Writing to a file is also easy in Perl:

 
 #!/usr/bin/perl open(FILE, ">/var/tmp/foobar")  die "unable to write to file"; print FILE "This is the first line of text\n"; close(FILE); 

The greater-than sign before the filename indicates that you wish to open the file for writing. You can also open a file such that writes will append to any text already present instead of overwriting the file. Using two greater-than signs instead of one:

 
 #!/usr/bin/perl open(FILE, ">>/var/tmp/log")  die "unable to append to file"; print FILE "This is the next log message\n"; close(FILE); 

10.3.10 Arguments

Command line arguments are stored in a hash named ARGV . Unlike in other languages, $ARGV[0] does not contain the name of the script itself; it is the first argument on the command line. $ARGV[1] is the second argument and so on. You can use $#ARGV as the index of the last argument:

 
 #!/usr/bin/perl if ($#ARGV < 0) { print "You must supply an argument to this program\n"; exit 1; } print "The first argument is $ARGV[0]\n"; 

10.3.11 Loops

Perl has the same kinds of loops as other languages, including for loops and while loops. A for loop is constructed as:

 
 #!/usr/bin/perl for $i (1 .. 4) { print "$i\n"; } 

which produces:

 
 Solaris% ./test.pl 1 2 3 4 

Here's example syntax for a while loop used to parse command line arguments:

 
 #!/usr/bin/perl $verbose=0; $quiet=0; while (@ARGV) { $arg=shift(@ARGV); if ($arg eq "-v") { $verbose=1; } elsif ($arg eq "-q") { $quiet=1; } else { print "Invalid argument $arg\n"; } } 

10.3.12 Using Command Output

Command output can be obtained in Perl with the use of single back quotes, just as in the Bourne shell:

 
 #!/usr/bin/perl $a='date'; print $a; 

Perl has built-in functions for retrieving the date and time, but this example illustrates the use of back quotes to obtain command output.

10.3.13 Subroutines

Subroutines in Perl are defined through use of the sub keyword:

 
 #!/usr/bin/perl sub max { my $a=shift, $b=shift; if ($a > $b) { return $a; } else { return $b; } } print "The max of 5 and 12 is " . max(5,12) . "\n"; 

Arguments to the subroutine are passed in the variable @_ , which is just like the variable $_ but now in the context of being a list, namely the list of arguments. Because this list of arguments is the "current thing," when the subroutine is entered you can simply call the shift function with no arguments to retrieve the first argument from the list. The word my is used to instruct Perl that the variables $a and $b are to be local to the procedure instead of visible to the entire script as Perl would have them be by default.

10.3.14 Exiting

There a number of ways to exit a Perl script. You can use the exit function:

 
 #!/usr/bin/perl exit 0; 

Or you can use the die function, which prints an error message to standard error and exits with whatever the current error number is.

The script:

 
 #!/usr/bin/perl die "This script failed" 

produces the output:

 
 Solaris% ./test.pl This script failed at ./test.pl line 2. 

10.3.15 Perl for Network Monitoring Scripts

Because Perl has such good text and list manipulation abilities , it is often the perfect tool for collecting output from several other programs. Perl can extract the relevant data from the formatted output that those programs produce and store it in data structures such as lists and hashes. This data can then be sorted or manipulated as required and finally printed in any format you desire .



Open Source Network Administration
Linux Kernel in a Nutshell (In a Nutshell (OReilly))
ISBN: 130462101
EAN: 2147483647
Year: 2002
Pages: 85

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net