Now you know how to open a filehandle for output, overwriting any existing file with the same name. Suppose you wanted to make sure that there wasn't a file by that name (to keep you from accidentally blowing away your spreadsheet data or that important birthday calendar). If you were writing a shell script, you'd use something like
-e
filename
to test if the file exists. Similarly,
Perl uses
-e
$filevar
to test for the existence of the file named by the scalar value in
$filevar
. If this file exists, the result is true; otherwise it is false.[
] For example:
$name = "index.html";
if (-e $name) {
print "I see you already have a file named $name\n";
} else {
print "Perhaps you'd like to make a file called $name\n";
}
The operand of the
-e
operator is really just any scalar expression that evaluates to some string, including a string literal. Here's an example that checks to see whether both
index.html
and
index.cgi
exist in the current directory:
if (-e "index.html" && -e "index.cgi") {
print "You have both styles of index files here.\n";
}
Other operators are defined as well. For example,
-r
$filevar
returns true if the file named in
$filevar
exists and is readable. Similarly,
-w
$filevar
tests whether it is writable. Here's an example that tests a user-specified filename for both readability and writability:
print "where? ";
$filename = <STDIN>;
chomp $filename; # toss pesky newline
if (-r $filename && -w $filename) {
# file exists, and I can read and write it
...
}
Many more file tests are available.
Table 10.1
gives the complete list.
Table 10.1: File Tests and Their Meanings
File Test
|
Meaning
|
-r
|
File or directory is readable
|
-w
|
File or directory is writable
|
-x
|
File or directory is executable
|
-o
|
File or directory is owned by user
|
-R
|
File or directory is readable by real user, not effective user (differs from
-r
for setuid programs)
|
-W
|
File or directory is writable by real user, not effective user (differs from
-w
for setuid programs)
|
-X
|
File or directory is executable by real user, not effective user (differs from
-x
for setuid programs)
|
-O
|
File or directory is owned by real user, not effective user (differs from
-o
for setuid programs)
|
-e
|
File or directory exists
|
-z
|
File exists and has zero size (directories are never empty)
|
-s
|
File or directory exists and has nonzero size (the value is the size in bytes)
|
-f
|
Entry is a plain file
|
-d
|
Entry is a directory
|
-l
|
Entry is a symlink
|
-S
|
Entry is a socket
|
-p
|
Entry is a named pipe (a "fifo")
|
-b
|
Entry is a block-special file (like a mountable disk)
|
-c
|
Entry is a character-special file (like an I/O device)
|
-u
|
File or directory is setuid
|
-g
|
File or directory is setgid
|
-k
|
File or directory has the sticky bit set
|
-t
|
isatty()
on the filehandle is true
|
-T
|
File is "text"
|
-B
|
File is "binary"
|
-M
|
Modification age in days
|
-A
|
Access age in days
|
-C
|
Inode-modification age in days
|
Most of these tests return a simple true-false condition. A few don't, so let's talk about them.
The
-s
operator does return true if the file is nonempty, but it's a particular kind of true. It's the length in bytes of the file, which evaluates as true for a nonzero number.
The age operators
-M
,
-A
, and
-C
(yes, they're uppercase) return the number of days since the file was last modified, accessed, or had its inode changed.[
] (The inode contains all of the information about the file except for its contents: see the
stat
system call manpage for details.) This age value is fractional with a resolution of one second: 36 hours is returned as 1.5 days. If you compare the age with a whole number (say three), you'll get only the files that were changed exactly that many days ago, not one second more or less. This means you'll probably want a range comparison[
] rather than an exact comparison to get files that are between three and four days old.
These operators can operate on filehandles as well as filenames. Giving a filehandle for the operand is all it takes. So to test whether the file opened as
SOMEFILE
is executable, you can use:
if (-x SOMEFILE) {
# file open on SOMEFILE is executable
}
If you leave the filename or filehandle parameter off (that is, you have just
-r
or
-s
), the default operand is the file named in the
$_
variable (there it is again!). So, to test a list of filenames to see which ones are readable, it's as simple as this:
foreach (@some_list_of_filenames) {
print "$_ is readable\n" if -r; # same as -r $_
}