-X FILEHANDLE
-X EXPR
-X DIRHANDLE
-X

文件测试,其中 X 是下面列出的字母之一。此一元运算符接受一个参数,可以是文件名、文件句柄或目录句柄,并测试关联的文件以查看其是否满足某些条件。如果省略参数,则测试 $_,除了 -t,它测试 STDIN。除非另有说明,否则它对真返回 1,对假返回 ''。如果文件不存在或无法检查,它将返回 undef 并设置 $!(errno)。除了 -l 测试之外,它们都遵循符号链接,因为它们使用 stat() 而不是 lstat()(因此悬空符号链接无法检查,因此将报告失败)。

尽管名称很奇怪,但优先级与任何其他命名一元运算符相同。运算符可以是以下任何一个

    -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 (is empty).
    -s  File has nonzero size (returns size in bytes).

    -f  File is a plain file.
    -d  File is a directory.
    -l  File is a symbolic link (false if symlinks aren't
        supported by the file system).
    -p  File is a named pipe (FIFO), or Filehandle is a pipe.
    -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 an ASCII or UTF-8 text file (heuristic guess).
    -B  File is a "binary" file (opposite of -T).

    -M  Script start time minus file modification time, in days.
    -A  Same for access time.
    -C  Same for inode change time (Unix, may differ for other
	platforms)

示例

while (<>) {
    chomp;
    next unless -f $_;  # ignore specials
    #...
}

请注意,-s/a/b/ 不会执行否定替换。但是,-exp($foo) 仍然按预期工作:只有紧跟在减号后面的单个字母被解释为文件测试。

这些运算符不受上述“看起来像函数规则”的约束。也就是说,运算符后面的左括号不会影响后续代码中构成参数的代码量。将左括号放在运算符之前以将其与后续代码隔开(当然,这仅适用于优先级高于一元运算符的运算符)。

-s($file) + 1024   # probably wrong; same as -s($file + 1024)
(-s $file) + 1024  # correct

文件权限操作符-r-R-w-W-x-X的解释默认情况下仅基于文件的模式以及用户的uid和gid。可能还有其他原因导致您无法实际读取、写入或执行文件:例如网络文件系统访问控制、ACL(访问控制列表)、只读文件系统和无法识别的可执行文件格式。请注意,使用这六个特定操作符来验证某个操作是否可行通常是一个错误,因为它可能会出现竞争条件。

另请注意,对于本地文件系统上的超级用户,-r-R-w-W测试始终返回1,而-x-X如果模式中设置了任何执行位,则返回1。因此,由超级用户运行的脚本可能需要执行stat来确定文件的实际模式,或者暂时将其有效uid设置为其他值。

如果您使用ACL,则有一个名为filetest的pragma,它可能比裸stat模式位产生更准确的结果。在use filetest 'access'下,上述文件测试将测试是否可以使用access(2)系列系统调用授予(不授予)权限。另请注意,在此pragma下,即使没有设置执行权限位(也没有任何额外的执行权限ACL),-x-X测试也可能返回true。这种奇怪现象是由于底层系统调用的定义造成的。另请注意,由于use filetest 'access'的实现,当此pragma生效时,_特殊文件句柄不会缓存文件测试的结果。有关更多信息,请阅读filetestpragma的文档。

-T-B测试的工作原理如下。检查文件的第一个块或更多块,以查看它是否为包含非ASCII字符的有效UTF-8。如果是,则为-T文件。否则,将检查文件相同部分的奇特字符,例如奇怪的控制代码或高位设置的字符。如果超过三分之一的字符是奇特的,则为-B文件;否则为-T文件。此外,在检查部分中包含零字节的任何文件都被视为二进制文件。(如果在包含LC_CTYPEuse locale范围内执行,则奇特字符是当前区域设置中任何不可打印的字符或空格。)如果-T-B用于文件句柄,则检查当前IO缓冲区而不是第一个块。-T-B在空文件或测试文件句柄时处于EOF的文件上都返回true。因为您必须读取文件才能执行-T测试,所以在大多数情况下,您希望首先对文件使用-f,例如next unless -f $file && -T $file

如果任何文件测试(或statlstat操作符)被赋予由单个下划线组成的特殊文件句柄,则使用先前文件测试(或stat操作符)的stat结构,从而节省了系统调用。(这在-t中不起作用,您需要记住lstat-l在stat结构中保留符号链接的值,而不是实际文件。)(此外,如果stat缓冲区由lstat调用填充,则-T-B将使用stat _的结果重置它。)示例

print "Can do.\n" if -r $a || -w _ || -x _;

stat($filename);
print "Readable\n" if -r _;
print "Writable\n" if -w _;
print "Executable\n" if -x _;
print "Setuid\n" if -u _;
print "Setgid\n" if -g _;
print "Sticky\n" if -k _;
print "Text\n" if -T _;
print "Binary\n" if -B _;

从 Perl 5.10.0 开始,作为纯粹的语法糖,您可以堆叠文件测试运算符,例如 -f -w -x $file 等同于 -x $file && -w _ && -f _。(这仅仅是花哨的语法:如果您将 -f $file 的返回值用作另一个文件测试运算符的参数,则不会发生任何特殊操作。)

可移植性问题:perlport 中的 "-X"

为了避免让您的代码的潜在用户因神秘的语法错误而感到困惑,请在脚本开头添加类似以下内容

use v5.10;  # so filetest ops can stack