What is _ (single underscore) in Perl without $ or @?

I have some code like this:

if (!-d _ || !-o _ || ($vncUserDirUnderTmp && ($mode & 0777) != 0700)) {
    raise Exception("$prog: Wrong type or access mode of $vncUserDir.\n")
}

I could find information about @_ and $_ in Perl but not about _ alone. What does it mean in -d _ and -o _ here?


When used with a filetest (-X) operator the stat structure of the previous file test is used

If any of the file tests (or either the stat or lstat operator) is given the special filehandle consisting of a solitary underline, then the stat structure of the previous file test (or stat operator) is used, saving a system call.
...
Example:

stat($filename);  
print "Readable\n" if -r _;  
print "Writable\n" if -w _;
...

So in your example !-d _ tests whether the file last stat-ed isn't a directory.

Update  

The unusual _ is really a typeglob *_ but with operators expecting a filehandle the * may be omitted, like <*STDIN> may be written as <STDIN>. It is found in the symbol table

print *{$main::{_}}{IO}, "\n";   # -->  IO::Handle=IO(0x2311970)

In a one-liner the *_ gets set up only after calls to stat and _ are made.


When you call one of the file test operators (-f, -d, -s, etc) Perl actually makes a call to the operating system's stat function. The stat function returns a structure full of all sorts of interesting information about the file in question, but each of the file test operators only looks at one of the fields from that structure (is it a file? is it a directory? how big is it?)

It's common that you might want to know more that one piece of information about a file (is it a file? can I read it? can I execute it?) The naive way to write that is:

if (-f $file and -r $file and -x $file)

But that makes three calls to stat - with each one of them only looking at one of the fields from the structure. To mitigate that, Perl is clever and caches the results of the most recent call to stat. It is cached against the special filehandle _. So a more efficient way to write the same code is:

if (-f $file and -r _ and -x _)

That only makes one call to stat.

Since Perl 5.10, you can also use "stacked file tests" and write this code as:

if (-x -r -f $file) # Note reversed order of operators

Update: perldoc says this about stacked file operators.

As of Perl 5.10.0, as a form of purely syntactic sugar, you can stack file test operators, in a way that -f -w -x $file is equivalent to"-x $file && -w _ && -f _. (This is only fancy syntax: if you use the return value of -f $file as an argument to another filetest operator, no special magic will happen.)