As we alluded to earlier, Perl is also a mathematical language. This is true at several levels, from low-level bitwise logical operations, up through number and set manipulation, on up to larger predicates and abstractions of various sorts. And as we all know from studying math in school, mathematicians love strange symbols. What's worse, computer scientists have come up with their own versions of these strange symbols. Perl has a number of these strange symbols too, but take heart, most are borrowed directly from C, FORTRAN, sed(1) or awk(1), so they'll at least be familiar to users of those languages.
Perl's built-in operators may be classified by number of operands into unary, binary, and trinary operators. They may be classified by whether they're infix operators or prefix operators. They may also be classified by the kinds of objects they work with, such as numbers, strings, or files. Later, we'll give you a table of all the operators, but here are some to get you started.
|Addition||Sum of |
|Multiplication||Product of |
|Modulus||Remainder of |
Yes, we left subtraction and division out of Table 1.2. But we suspect you can figure out how they should work. Try them and see if you're right. (Or cheat and look in the index.) Arithmetic operators are evaluated in the order your math teacher taught you (exponentiation before multiplication, and multiplication before addition). You can always use parentheses to make it come out differently.
$a = 123; $b = 456; print $a + $b; # prints 579 print $a . $b; # prints 123456
$a = 123; $b = 3; print $a * $b; # prints 369 print $a x $b; # prints 123123123
These string operators bind as tightly as their corresponding arithmetic operators. The repeat operator is a bit unusual in taking a string for its left argument but a number for its right argument. Note also how Perl is automatically converting from numbers to strings. You could have put all the literal numbers above in quotes, and it would still have produced the same output. Internally though, it would have been converting in the opposite direction (that is, from strings to numbers).
A couple more things to think about. String concatenation is also implied by the interpolation that happens in double-quoted strings. When you print out a list of values, you're also effectively concatenating strings. So the following three statements produce the same output:
print $a . ' is equal to ' . $b . "\n"; # dot operator print $a, ' is equal to ', $b, "\n"; # list print "$a is equal to $b\n"; # interpolation
Which of these you use in any particular situation is entirely up to you.
The x operator may seem relatively worthless at first glance, but it is quite useful at times, especially for things like this:
print "-" x $scrwid, "\n";
which draws a line across your screen, presuming your screen width
Although it's not exactly a mathematical operator, we've already made
extensive use of the simple assignment operator,
=. Try to remember
= means "gets set to" rather than "equals". (There is also a
mathematical equality operator
== that means "equals", and if you
start out thinking about the difference between them now, you'll save
yourself a lot of headache later.)
Like the operators above, assignment operators are binary infix operators, which means they have an operand on either side of the operator. The right operand can be any expression you like, but the left operand must be a valid lvalue (which, when translated to English, means a valid storage location like a variable, or a location in an array). The most common assignment operator is simple assignment. It determines the value of the expression on its right side, and sets the variable on the left side to that value:
$a = $b; $a = $b + 5; $a = $a * 3;
Notice the last assignment refers to the same variable twice; once for the computation, once for the assignment. There's nothing wrong with that, but it's a common enough operation that there's a shortcut for it (borrowed from C). If you say:
lvalue operator= expression
it is evaluated as if it were:
lvalue = lvalue operator expression
except that the lvalue is not computed twice. (This only makes a difference if evaluation of the lvalue has side effects. But when it does make a difference, it usually does what you want. So don't sweat it.)
So, for example, you could write the above as:
$a *= 3;
which reads "multiply
$a by 3". You can do this with almost any
binary operator in Perl, even some that you can't do it with in C:
$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 set.
Line 6 of our grade example contains two string concatenations, one
of which is an assignment operator. And line 14 contains a
Regardless of which kind of assignment operator you use, the final value is returned as the value of the assignment as a whole. (This is unlike, say, Pascal, in which assignment is a statement and has no value.) This is why we could say:
chop($number = <STDIN>);
and have it chop the final value of
$number. You also frequently see
assignment as the condition of a while loop, as in line 4 of our grade
$variable += 1 weren't short enough, Perl borrows from C
an even shorter way to increment a variable. The autoincrement and
autodecrement operators simply add (or subtract) one from the value of the
variable. They can be placed on either side of the variable, depending on
when you want them to be evaluated (see Table 1.3).
|Autoincrement||Add 1 to |
|Autodecrement||Subtract 1 from |
If you place one of the auto operators before the variable, it is known as a pre-incremented (pre-decremented) variable. Its value will be changed before it is referenced. If it is placed after the variable, it is known as a post-incremented (post-decremented) variable and its value is changed after it is used. For example:
$a = 5; # $a is assigned 5 $b = ++$a; # $b is assigned the incremented value of $a, 6 $c = $a--; # $c is assigned 6, then $a is decremented to 5
Line 15 of our grade example increments the number of scores by one, so
that we'll know how many scores we're averaging the grade over. It uses
a post-increment operator (
$scores++), but in this case it doesn't
matter, since the expression is in a void context, which is just a funny
way of saying that the expression is being evaluated only for the side
effect of incrementing the variable. The value returned is being thrown
 The optimizer will notice this and optimize the post-increment into a pre-increment, because that's a little more efficient to execute. (You didn't need to know that, but we hoped it would cheer you up.)
Logical operators, also known as "short-circuit" operators, allow the program to make decisions based on multiple criteria, without using nested conditionals. They are known as short-circuit because they skip evaluating their right argument if evaluating their left argument is sufficient to determine the overall value.
Perl actually has two sets of logical operators, a crufty old set borrowed from C, and a nifty new set of ultralow-precedence operators that parse more like people expect them to parse, and are also easier to read. (Once they're parsed, they behave identically though.) See Table 1.4 for examples of logical operators.
|Not||True if |
|Not||True if |
Since the logical operators "short circuit" the way they do, they're often used to conditionally execute code. The following line (from our grade example) tries to open the file grades.
open(GRADES, "grades") or die "Can't open file grades: $!\n";
If it opens the file, it will jump to the next line of the program. If it can't open the file, it will provide us with an error message and then stop execution.
Literally, the above message means "Open grades or die!" Besides being another example of natural language, the short-circuit operators preserve the visual flow. Important actions are listed down the left side of the screen, and secondary actions are hidden off to the right. (The $! variable contains the error message returned by the operating system - see "Special Variables" in Chapter 2). Of course, these logical operators can also be used within the more traditional kinds of conditional constructs, such as the if and while statements.
Comparison, or relational, operators tell us how two scalar values
(numbers or strings) relate to each other. There are two sets of
operators - one does numeric comparison and the other
does string comparison. (In either case, the arguments will be "coerced"
to have the appropriate type first.) Table 1.5 assumes
$b are the left and right arguments, respectively.
|Equal||True if |
|Not equal||True if |
|Less than||True if |
|Greater than||True if |
|Less than or equal||True if |
|Comparison||0 if equal, 1 if |
 Some folks feel that such redundancy is evil because it keeps a language from being minimalistic, or orthogonal. But Perl isn't an orthogonal language; it's a diagonal language. By which we mean that Perl doesn't force you to always go at right angles. Sometimes you just want to follow the hypotenuse of the triangle to get where you're going. TMTOWTDI is about shortcuts. Shortcuts are about efficiency.
The file test operators allow you to test whether certain file attributes are set before you go and blindly muck about with the files. For example, it would be very nice to know that the file /etc/passwd already exists before you go and open it as a new file, wiping out everything that was in there before. See Table 1.6 for examples of file test operators.
|Exists||True if file named in |
|Readable||True if file named in |
|Writable||True if file named in |
|Directory||True if file named in |
|File||True if file named in |
|Text File||True if file named in |
Here are some examples:
-e "/usr/bin/perl" or warn "Perl is improperly installed\n"; -f "/vmunix" and print "Congrats, we seem to be running BSD Unix\n";
Note that a regular file is not the same thing as a text file. Binary files like /vmunix are regular files, but they aren't text files. Text files are the opposite of binary files, while regular files are the opposite of irregular files like directories and devices.
There are a lot of file test operators, many of which we didn't list. Most of the file tests are unary Boolean operators: they take only one operand, a scalar that evaluates to a file or a filehandle, and they return either a true or false value. A few of them return something fancier, like the file's size or age, but you can look those up when you need them.