Perl has many operators that you can use to test different aspects of a file. For example, you can use the -e operator to ensure that a file exists before deleting it. Or, you can check that a file can be written to before appending to it. By checking the feasibility of the impending file operation, you can reduce the number of errors that your program will encounter.
A complete list of the operators used to test files is given in Table 9.1
Operator | Description |
---|---|
-A OPERAND | Returns the access age of OPERAND when the program started. |
-bOPERAND | Tests if OPERAND is a block device. |
-BOPERAND | Tests if OPERAND is a binary file. If OPERAND is a file handle, |
then the current buffer is examined, instead of the file itself. | |
-c OPERAND | Tests if OPERAND is a character device. |
-COPERAND | Returns the inode change age of OPERAND when the program started. |
-dOPERAND | Tests if OPERAND is a directory. |
-eOPERAND | Tests if OPERAND exists. |
-fOPERAND | Tests if OPERAND is a regular file as opposed to a directory, |
symbolic link or other type of file. | |
-g OPERAND | Tests if OPERAND has the setgid bit set. |
-kOPERAND | Tests if OPERAND has the sticky bit set. |
-lOPERAND | Tests if OPERAND is a symbolic link. Under DOS, |
this operator always will return false. | |
-M OPERAND | Returns the age of OPERAND in days when the program started. |
-oOPERAND | Tests if OPERAND is owned by the effective uid. |
Under DOS, it always returns true. | |
-OOPERAND | Tests if OPERAND is owned by the read uid/gid. |
Under DOS, it always returns true. | |
-pOPERAND | Tests if OPERAND is a named pipe. |
-rOPERAND | Tests if OPERAND can be read from. |
-ROPERAND | Tests if OPERAND can be read from by the real uid/gid. |
Under DOS, it is identical to -r. | |
-sOPERAND | Returns the size of OPERAND in bytes. |
Therefore, it returns true if OPERAND is non-zero. | |
-SOPERAND | Tests if OPERAND is a socket. |
-tOPERAND | Tests if OPERAND is opened to a tty. |
-TOPERAND | Tests if OPERAND is a text file. If OPERAND is a file handle, |
then the current buffer is examined, instead of the file itself. | |
-uOPERAND | Tests if OPERAND has the setuid bit set. |
-w OPERAND | Tests if OPERAND can be written to. |
-W OPERAND | Tests if OPERAND can be written to by the real uid/gid. |
Under DOS, it is identical to -w. | |
-xOPERAND | Tests if OPERAND can be executed. |
-XOPERAND | Tests if OPERAND can be executed by the real uid/gid. |
Under DOS, it is identical to -x. | |
-zOPERAND | Tests if OPERAND size is zero. |
Note If the OPERAND is not specified in the file test, the $ variable will be used instead.
The operand used by the file tests can be either a file handle or a file name. The file tests work by internally calling the operating system to determine information about the file in question. The operators will evaluate to true if the test succeeds and false if it does not.
If you need to perform two or more tests on the same file, you use the special underscore (_) file handle. This tells Perl to use the file information for the last system query and saves time. However, the underscore file handle does have some caveats. It does not work with the -t operator. In addition, the lstat() function and -l test will leave the system buffer filled with information about a symbolic link, not a real file.
The -T and -B file tests will examine the first block or so of the file. If more than 10 percent of the bytes are non-characters or if a null byte is encountered, then the file is considered a binary file. Binary files are normally data files, as opposed to text or human-readable files. If you need to work with binary files, be sure to use the binmode() file function, which is described in the section, "Example: Binary Files," later in this chapter.
Using File Tests
For our first example with file tests, let's examine a list of files from the command line and determine if each is a regular file or a special file test.pl.
foreach (@ARGV) { print; print((-f) ? " -REGULAR\n" : " -SPECIAL\n") }
When this program is run using the following command line:
perl -w 09lst01.pl \perl5 perl.exe \windows
the following is displayed:
09lst01.pl -REGULAR \perl5 -SPECIAL perl.exe -REGULAR \windows -SPECIAL
Each of the directories listed on the command line were recognized as special files. If you want to ignore all special files in the command line, you do so like this test2.pl:
foreach (@ARGV) { next unless -f; # ignore all non-normal files. print; print((-f) ? " -REGULAR\n" : " -SPECIAL\n") }
When this program is run using the following command line:
perl -w 09lst01.pl \perl perl.exe \windows}
the following is displayed:
09lst01.pl -REGULAR perl.exe -REGULAR
Notice that only the regular file names are displayed. The two directories on the command line were ignored.
As mentioned above, you can use the underscore file handle to make two tests in a row on the same file so that your program can execute faster and use less system resources. This could be important if your application is time critical or makes many repeated tests on a large number of files size.pl.
foreach (@ARGV) { next unless -f; $fileSize = -s _; print("$_ is $fileSize bytes long.\n"); }
When this program is run using the following command line:
perl -w 09lst06.pl \perl5 09lst01.pl \windows perl.exe
the following is displayed:
09lst01.pl is 36 bytes long. perl.exe is 61952 bytes long.