As in the Unixshell, you can use different quoting mechanisms to make different kinds of values. Double quotation marks (double quotes) dovariable interpolationandbackslash interpolation(such as turning/ninto a newline) while single quotes suppress interpolation. And backquotes (the ones leaning to the left``) will execute an external program and return the output of the program, so you can capture it as a single string containing all the lines of output.
And while we haven't covered fancy values yet, we should point out that scalars may also hold references to other data structures, including subroutines and objects.$answer = 42; # an integer $pi = 3.14159265; # a "real" number $avocados = 6.02e23; # scientific notation $pet = "Camel"; # string $sign = "I love my $pet"; # string with interpolation $cost = 'It costs $100'; # string without interpolation $thence = $whence; # another variable's value $salsa = $moles * $avocados; # a gastrochemical expression $exit = system("vi $file"); # numeric status of a command $cwd = `pwd`; # string output from a command
$ary = /@myarray; # reference to a named array $hsh = /%myhash; # reference to a named hash $sub = /&mysub; # reference to a named subroutine $ary = [1,2,3,4,5]; # reference to an unnamed array $hsh = {Na => 19, Cl => 35}; # reference to an unnamed hash $sub = sub { print $state }; # reference to an unnamed subroutine $fido = new Camel "Amelia"; # reference to an object
The original value of $camelsis a string, but it is converted to a number to add 1to it, and then converted back to a string to be printed out as 124.$camels = '123'; print $camels + 1, "/n";
Similarly, a reference behaves as a reference when you give it a "dereference" context, but otherwise acts like a simple scalar value. For example, we might say:
$fido = new Camel "Amelia"; if (not $fido) { die "dead camel"; } $fido->saddle();
Conversely, if you use @homein a list context, such as on the right side of a list assignment, you get back out the same list you put in. So you could set four scalar variables from the array like this:@home = ("couch", "chair", "table", "stove");
These are called list assignments. They logically happen in parallel, so you can swap two variables by saying:($potato, $lift, $tennis, $pipe) = @home;
($alpha,$omega) = ($omega,$alpha);
Suppose you wanted to translate abbreviated day names to the corresponding full names. You could write the following list assignment:
But that's rather difficult to read, so Perl provides the =>(equals sign, greater-than sign) sequence as an alternative separator to the comma. Using this syntactic sugar (and some creative formatting), it is much easier to see which strings are the keys and which strings are the associated values.%longday = ("Sun", "Sunday", "Mon", "Monday", "Tue", "Tuesday", "Wed", "Wednesday", "Thu", "Thursday", "Fri", "Friday", "Sat", "Saturday");
%longday = ( "Sun" => "Sunday", "Mon" => "Monday", "Tue" => "Tuesday", "Wed" => "Wednesday", "Thu" => "Thursday", "Fri" => "Friday", "Sat" => "Saturday", );
Linguistically, the relationship encoded in a hash is genitive or possessive, like the word "of" in English, or like "'s". The wifeofAdam is Eve, so we write:
$wife{"Adam"} = "Eve";
But that wouldn't do what you want, because even parentheses and commas are not powerful enough to turn a list into a scalar in Perl. (Parentheses are used for syntactic grouping, and commas for syntactic separation.) Rather, you need to tell Perl explicitly that you want to pretend that a list is a scalar. It turns out that square brackets are powerful enough to do that:$wife{"Jacob"} = ("Leah", "Rachel", "Bilhah", "Zilpah"); # WRONG
$wife{"Jacob"} = ["Leah", "Rachel", "Bilhah", "Zilpah"]; # ok
That would be more or less equivalent to saying:$kids_of_wife{"Jacob"} = { "Leah" => ["Reuben", "Simeon", "Levi", "Judah", "Issachar", "Zebulun"], "Rachel" => ["Joseph", "Benjamin"], "Bilhah" => ["Dan", "Naphtali"], "Zilpah" => ["Gad", "Asher"], };
$kids_of_wife{"Jacob"}{"Leah"}[0] = "Reuben"; $kids_of_wife{"Jacob"}{"Leah"}[1] = "Simeon"; $kids_of_wife{"Jacob"}{"Leah"}[2] = "Levi"; $kids_of_wife{"Jacob"}{"Leah"}[3] = "Judah"; $kids_of_wife{"Jacob"}{"Leah"}[4] = "Issachar"; $kids_of_wife{"Jacob"}{"Leah"}[5] = "Zebulun"; $kids_of_wife{"Jacob"}{"Rachel"}[0] = "Joseph"; $kids_of_wife{"Jacob"}{"Rachel"}[1] = "Benjamin"; $kids_of_wife{"Jacob"}{"Bilhah"}[0] = "Dan"; $kids_of_wife{"Jacob"}{"Bilhah"}[1] = "Naphtali"; $kids_of_wife{"Jacob"}{"Zilpah"}[0] = "Gad"; $kids_of_wife{"Jacob"}{"Zilpah"}[1] = "Asher";
Perl also has several ways of topicalizing. One important topicalizer is thepackagedeclaration. Suppose you want to talk aboutCamels in Perl. You'd likely start off yourCamelmodule by saying:
package Camel;
When you saypackage Camel, you're starting a new package. But sometimes you just want to borrow the nouns and verbs of an existing package. Perl lets you do that with ausedeclaration, which not only borrows verbs from another package, but also checks that the module you name is loaded in from disk. In fact, youmustsay something like:
before you say:use Camel;
$fido = new Camel "Amelia";
In fact, some of the built-in modules don't actually introduce verbs at all, but simply warp the Perl language in various useful ways. These special modules we callpragmas. For instance, you'll often see people use the pragmastrict, like this:
use strict;
As you can see, the name you pick for the filehandle is arbitrary. Once opened, the filehandle SESAMEcan be used to access the file or pipe until it is explicitly closed (with, you guessed it, close(SESAME)), or until the filehandle is attached to another file by a subsequent openon the same filehandle.open(SESAME, "filename") # read from existing file open(SESAME, "<filename") # (same thing, explicitly) open(SESAME, ">filename") # create file and write to it open(SESAME, ">>filename") # append to existing file open(SESAME, "| output-pipe-command") # set up an output filter open(SESAME, "input-pipe-command |") # set up an input filter
An example using theSTDINfilehandle to read an answer supplied by the user would look something like this:
print STDOUT "Enter a number: "; # ask for a number $number = <STDIN>; # input the number print STDOUT "The number is $number./n"; # print the number
If you try the previous example, you may notice that you get an extra blank line. This happens because the line-reading operation does not automatically remove the newline from your input line (your input would be, for example, "9/n"). For those times when you do want to remove the newline, Perl provides thechopandchompfunctions.chopwill indiscriminately remove (and return) the last character of the string, whilechompwill only remove the end of record marker (generally, "/n") and return the number of characters so removed.You'll often see this idiom for inputting a single line:
chop($number = <STDIN>); # input number and remove newline
$a + $b | Addition | Sum of$aand$b |
$a * $b | Multiplication | Product of$aand$b |
$a % $b | Modulus | Remainder of$adivided by$b |
$a ** $b | Exponentiation | $ato the power of$b |
Perl defines a separate operator (.) for string concatenation:
$a = 123; $b = 456; print $a + $b; # prints 579 print $a . $b; # prints 123456
There's also a "multiply" operator for strings, called therepeatoperator. Again, it's a separate operator (x) to keep it distinct from numeric multiplication:
$a = 123; $b = 3; print $a * $b; # prints 369 print $a x $b; # prints 123123123
Thexoperator may seem relatively worthless at first glance, but it is quite useful at times, especially for things like this:
which draws a line across your screen, presuming $scrwidcontains your screen width, and not your screw identifier.print "-" x $scrwid, "/n";
$line .= "/n"; # Append newline to $line. $fill x= 80; # Make string $fill into 80 repeats of itself. $val ||= "2"; # Set $val to 2 if it isn't already "true".
++$a, $a++ | Autoincrement | Add 1 to$a |
--$a, $a-- | Autodecrement | Subtract 1 from$a |
Here are a few of the file test operators:
You might use them like this:
-e "/usr/bin/perl" or warn "Perl is improperly installed/n"; -f "/vmlinuz" and print "I see you are a friend of Linus/n";
Truth in Perl is always evaluated in a scalar context.Other than that, no type coercion is done. So here are the rules for the various kinds of values a scalar can hold:
"0.00" + 0 # would become the number 0 (coerced by the +), so false. /$a # is a reference to $a, so true, even if $a is false. undef() # is a function returning the undefined value, so false.
if ($city eq "New York") {
print "New York is northeast of Washington, D.C./n";
}
elsif ($city eq "Chicago") {
print "Chicago is northwest of Washington, D.C./n";
}
elsif ($city eq "Miami") {
print "Miami is south of Washington, D.C. And much warmer!/n";
}
else {
print "I don't know where $city is, sorry./n";
}
unless ($destination eq $home) { print "I'm not going home./n"; }
Perl has four main iterative statement types:while,until,for, andforeach. These statements allow a Perl program to repeatedly execute the same code.
In fact, almost everything is designed to work smoothly in a conditional (Boolean) context. If you mention an array in a scalar context, thelengthof the array is returned. So you often see command-line arguments processed like this:
The shiftoperator removes one element from the argument list each time through the loop (and returns that element). The loop automatically exits when array @ARGVis exhausted, that is, when its length goes to 0. And 0 is already false in Perl. In a sense, the array itself has become "false". [21]while (@ARGV) { process(shift @ARGV); }
[21] This is how Perl programmers think. So there's no need to compare 0 to 0 to see if it's false. Despite the fact that other languages force you to, don't go out of your way to write explicit comparisons likewhile (@ARGV != 0). That's just inefficient for both you and the computer. And anyone who has to maintain your code.
for ($sold = 0; $sold < 10000; $sold += $purchase) { $available = 10000 - $sold; print "$available tickets are available. How many would you like: "; $purchase = <STDIN>; chomp($purchase);
foreach $user (@users) { if (-f "$home{$user}/.nexrc") { print "$user is cool... they use a perl-aware vi!/n"; } }
It's possible to break out of multilevel loops by labeling your loops and specifying which loop you want to break out of. Together with statement modifiers (another form of conditional which we'll talk about later), this can make for extremely readable loop exits (if you happen to think English is readable):foreach $user (@users) { if ($user eq "root" or $user eq "lp") { next; } if ($user eq "special") { print "Found the special account./n"; # do some processing last; } }
LINE: while ($line = <ARTICLE>) { last LINE if $line eq "/n"; # stop on first blank line next LINE if $line =~ /^#/; # skip comment lines # your ad here }
First and foremost, they're used in conditionals to determine whether a string matches a particular pattern, because in a Boolean context they return true and false. So when you see something that looks like/foo/in a conditional, you know you're looking at an ordinarypattern-matchingoperator:
if (/Windows 95/) { print "Time to upgrade?/n" }
Second, if you can locate patterns within a string, you can replace them with something else. So when you see something that looks likes/foo/bar/, you know it's asking Perl to substitute "bar" for "foo", if possible. We call that thesubstitutionoperator. It also happens to return true or false depending on whether it succeeded, but usually it's evaluated for its side effect:
s/Windows/Linux/;
Finally, patterns can specify not only where something is, but also where itisn't. So thesplitoperator uses a regular expression to specify where the data isn't. That is, the regular expression defines theseparatorsthat delimit the fields of data. Our Average Example has a couple of trivial examples of this. Lines 5 and 12 each split strings on the space character in order to return a list of words. But you can split on any separator you can specify with a regular expression:
($good, $bad, $ugly) = split(/,/, "vi,emacs,teco");
Because certain classes like the alphabetics are so commonly used, Perl defines shortcuts for them:
Whitespace | [ /t/n/r/f] | /s |
Word character | [a-zA-Z_0-9] | /w |
Digit | [0-9] | /d |
Note that these matchsinglecharacters. A/wwill match any single word character, not an entire word. (Remember that+quantifier? You can say/w+to match a word.) Perl also provides the negation of these classes by using the uppercased character, such as/Dfor a nondigit character.
Certain combinations of minimum and maximum occur frequently, so Perl defines special quantifiers for them. We've already seen+, which is the same as{1,}, or "at least one of the preceding item". There is also*, which is the same as{0,}, or "zero or more of the preceding item", and?, which is the same as{0,1}, or "zero or one of the preceding item" (that is, the preceding item is optional).
You need to be careful of a couple things about quantification. First of all, Perl quantifiers are by defaultgreedy. This means that they will attempt to match as much as they can as long as the whole pattern still matches.The other point to be careful about is that regular expressions will try to match asearlyas possible. This even takes precedence over being greedy. Since scanning happens left-to-right, this means that the pattern will match as far left as possible, even if there is some other place where it could match longer.
There's one other thing you need to know. By default, quantifiers apply to a single preceding character, so/bam{2}/will match "bamm" but not "bambam". To apply a quantifier to more than one character, use parentheses. So to match "bambam", use the pattern/(bam){2}/.
You can forcenon greedy, minimal matching by placing a question mark after any quantifier.That.*?will now try to match as few characters as possible, rather than as many as possible.
The special symbol/bmatches at a word boundary.
If it is the first character of a pattern, the caret (^) matches the "nothing" at the beginning of the string.
The dollar sign ($) works like the caret, except that it matches the "nothing" at the end of the string instead of the beginning.