Some of the "functions" described in Chapter 29 are really unary operators. Table 3.2 lists all the named unary operators.
Table 3-2. Named Unary Operators
- X (file
tests) | gethostbyname | localtime | return |
alarm | getnetbyname | lock | rmdir |
caller | getpgrp | log | scalar |
chdir | getprotobyname | lstat | sin |
chroot | glob | my | sleep |
cos | gmtime | oct | sqrt |
defined | goto | ord | srand |
delete | hex | quotemeta | stat |
do | int | rand | uc |
eval | lc | readlink | ucfirst |
exists | lcfirst | ref | umask |
exit | length | require | undef |
Unary operators have a higher precedence than some of the binary operators. For example:
sleep 4 | 3;
does not sleep for 7 seconds; it sleeps for 4 seconds and then
takes the return value of sleep
(typically zero)
and bitwise ORs that with 3, as if the expression were parenthesized
as:
(sleep 4) | 3;
Compare this with:
print 4 | 3;
which does take the value of 4 ORed with 3 before printing it (7 in this case), as if it were written:
print (4 | 3);
This is because print
is a list operator, not
a simple unary operator. Once you've learned which operators are list
operators, you'll have no trouble telling unary operators and list
operators apart. When in doubt, you can always use parentheses to turn
a named unary operator into a function. Remember, if it looks like a
function, it is a function.
Another funny thing about named unary operators is that
many of them default to $_
if you don't supply an
argument. However, if you omit the argument but the token following
the named unary operator looks like it might be the start of an
argument, Perl will get confused because it's expecting a term.
Whenever the Perl tokener gets to one of the characters listed in
Table 3.3, the tokener
returns different token types depending on whether it expects a term
or operator.
Table 3-3. Ambiguous Characters
Character | Operator | Term |
---|---|---|
+ | Addition | Unary plus |
- | Subtraction | Unary minus |
* | Multiplication | *typeglob |
/ | Division | /pattern/ |
< | Less than, left shift | <HANDLE>, <<END |
. | Concatenation | .3333 |
? | ? : | ?pattern? |
% | Modulo | %assoc |
& | &, && | &subroutine |
So a typical boo-boo is:
next if length < 80;
in which the <
looks to the parser like
the beginning of the <>
input symbol (a term)
instead of the "less than" (an operator) you were thinking of. There's
really no way to fix this and still keep Perl pathologically eclectic.
If you're so incredibly lazy that you cannot bring yourself to type
the two characters $_
, then use one of these
instead:
next if length() < 80; next if (length) < 80; next if 80 > length; next unless length >= 80;
When a term is expected, a minus sign followed by a
single letter will always be interpreted as a file
test operator. A file test operator is a unary operator
that takes one argument, either a filename or a filehandle, and tests
the associated file to see whether something is true about it. If the
argument is omitted, it tests $_
, except for
-t
, which tests STDIN
. Unless
otherwise documented, it returns 1
for true and ""
for false, or the undefined value if the file doesn't exist or is
otherwise inaccessible. Currently implemented file test operators are
listed in Table
3.4.
Table 3-4. File Test Operators
Operator | Meaning |
---|---|
-r | File is readable by effective UID/GID. |
-w | File is writable by effective UID/GID. |
-x | File is executable by effective UID/GID. |
-o | File is owned by effective UID. |
-R | File is readable by real UID/GID. |
-W | File is writable by real UID/GID. |
-X | File is executable by real UID/GID. |
-O | File is owned by real UID. |
-e | File exists. |
-z | File has zero size. |
-s | File has nonzero size (returns size). |
-f | File is a plain file. |
-d | File is a directory. |
-l | File is a symbolic link. |
-p | File is a named pipe (FIFO). |
-S | File is a socket. |
-b | File is a block special file. |
-c | File is a character special file. |
-t | Filehandle is opened to a tty. |
-u | File has setuid bit set. |
-g | File has setgid bit set. |
-k | File has sticky bit set. |
-T | File is a text file. |
-B | File is a binary file (opposite of
-T ). |
-M | Age of file (at startup) in days since modification. |
-A | Age of file (at startup) in days since last access. |
-C | Age of file (at startup) in days since inode change. |
Note that -s/a/b/
does not do a negated
substitution. Saying -exp($foo)
still works as
expected, however--only single letters following a minus are
interpreted as file tests.
The interpretation of the file permission operators
-r
, -R
, -w
,
-W
, -x
, and
-X
is based solely on the mode of the file and the
user and group IDs of the user. There may be other reasons you can't
actually read, write, or execute the file, such as Andrew File System
(AFS) access control lists.[3] Also note that for the superuser, -r
,
-R
, -w
, and
-W
always return 1, and -x
and
-X
return 1 if any execute bit is set in the mode.
Thus, scripts run by the superuser may need to do a
stat
in order to determine the actual mode of the
file or temporarily set the UID to something else.
The other file test operators don't care who you are. Anybody can use the test for "regular" files:
while (<>) { chomp; next unless -f $_; # ignore "special" files … }
The -T
and -B
switches work as follows. The first block or so of the file is
examined for strange characters such as control codes or bytes with
the high bit set (that don't look like UTF-8). If more than a third of
the bytes appear to be strange, it's a binary file; otherwise, it's a
text file. Also, any file containing ASCII NUL (