The -x File Tests

by Jeff Hunter, Sr. Database Administrator


The -x File Tests

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.[4] 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
    ...
}


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.[5] (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[6] rather than an exact comparison to get files that are between three and four days old.

[5] The age is measured relative to the time the program started, as captured in system time format in the $^T variable. It's possible to get negative numbers for these ages if the queried value refers to an event that happened after the program began.

[6] Or the int operator.

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 $_
}



Last modified on: Saturday, 18-Sep-2010 18:08:51 EDT
Page Count: 6982