Filehandles, files, directories
stat#
Get a file’s status information.
stat asks the operating system for the metadata record of a file —
size, ownership, permissions, timestamps, inode — and returns it as a
13-element list. It is the underlying primitive behind the -X file
tests (-e, -f, -r, …), behind modules like
File::stat, and behind any
script that needs to inspect a file without opening it. stat
dereferences symlinks and reports on the target; use lstat
to get the link itself.
Synopsis#
stat FILEHANDLE
stat EXPR
stat DIRHANDLE
stat
stat _
What you get back#
In list context, a 13-element list of numeric fields. In scalar
context, a boolean: true on success, false on failure. Either way,
on success the kernel’s stat buffer is cached in the special
filehandle _, which any subsequent stat, lstat, or
-X test can re-use without a new syscall.
On failure, list context returns the empty list and $!
is set to the errno value from the failed stat(2).
The fields, in order:
Index |
Field |
Meaning |
|---|---|---|
0 |
|
device number of the filesystem holding the file |
1 |
|
inode number |
2 |
|
file mode — type bits and permission bits combined |
3 |
|
number of hard links to the file |
4 |
|
numeric user ID of the owner |
5 |
|
numeric group ID of the owner |
6 |
|
device identifier, for character/block special files |
7 |
|
total size in bytes |
8 |
|
last access time, seconds since the epoch (1970-01-01 00:00 GMT) |
9 |
|
last modify time, seconds since the epoch |
10 |
|
inode change time, seconds since the epoch — not creation time |
11 |
|
preferred I/O block size for reads/writes against this file |
12 |
|
number of filesystem blocks actually allocated (often 512 B each) |
Field 2 (mode) packs both the file type and the permission bits
into one number. Mask with 07777 to see just the permissions; use
the S_IF* constants and S_IS* helpers from
Fcntl to test the type
portably.
my $mode = (stat($filename))[2];
printf "permissions are %04o\n", $mode & 07777;
Not every filesystem populates every field. atime, blksize,
and blocks may come back as 0 on filesystems that do not track
them (for instance some FUSE mounts or network filesystems); ctime
is not a portable “creation time” — it tracks the last change to
the inode itself (permissions, ownership, link count), not when
the file was first created.
Global state it touches#
$_— read whenstatis called with no argument.statwith noEXPRstats the filename held in$_, not the cached_handle.$!— set to theerrnoof the failedstat(2)syscall when the call fails.The special
_filehandle — a per-interpreter cache of the most recent successfulstat,lstat, or-Xresult. Passing_as the argument reuses that cached buffer and issues no syscall. Successful calls refresh it; failed calls leave the previous contents in place.
Examples#
Basic list-context unpack:
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
$atime, $mtime, $ctime, $blksize, $blocks) = stat($filename);
Pick out a single field with a list slice:
my $size = (stat($filename))[7];
my $mtime = (stat($filename))[9];
Scalar context as an existence-plus-readable-metadata probe:
if (stat($path)) {
my $size = (stat _)[7]; # reuse the cached buffer
print "size = $size\n";
} else {
warn "stat $path: $!";
}
Reusing the cache across an -X test and a stat:
if (-x $file && (($d) = stat(_)) && $d < 0) {
print "$file is executable NFS file\n";
}
Named-accessor access through File::stat:
use File::stat;
my $sb = stat($filename);
printf "file %s, size %s, perm %04o, mtime %s\n",
$filename, $sb->size, $sb->mode & 07777,
scalar localtime $sb->mtime;
Decoding the mode with Fcntl:
use Fcntl ':mode';
my $mode = (stat($filename))[2];
printf "permissions %04o\n", S_IMODE($mode);
print "is a directory\n" if S_ISDIR($mode);
Edge cases#
No argument:
stat;stats$_, not the cached_handle. To re-read the cache you must writestat(_)with the underscore as an explicit bareword.The
_bareword is special: it names the stat cache, not a file. Quoting it (stat("_")) stats a file literally called_in the current directory.Symlinks are followed:
statreports on the target of a symlink. For the link itself, uselstat. A broken symlink makesstatfail withENOENT;lstaton the same path succeeds.DIRHANDLE form: passing a directory handle from
opendirreturns the stat of the open directory itself. Not every platform supports this; on those that do not, the call fails and$!is set.Inode numbers may overflow integers: on filesystems with 64-bit inode numbers beyond Perl’s integer range,
inois returned as a decimal string to preserve the full value. Compare inode numbers witheq, not==, to stay correct on those filesystems.eqworks fine on numeric inodes too.ctimeis not creation time: it is the inode-change time — updated bychmod,chown,rename, link-count changes, and the file’s own writes. Linux exposes a true creation time (btime) viastatx(2), but that is not part ofstat’s return list.Zero fields on some filesystems:
atime(onnoatimemounts),blksize, andblocksmay be reported as0. Treat0as “unavailable”, not as a meaningful value.Scalar context does not populate
_on failure: a failedstatleaves the previous cached buffer untouched. Always check the return value before a follow-upstat(_)or-X _.Race windows: the metadata returned is a snapshot. Anything that acts on a path based on
stat’s result (permission checks, TOCTOU patterns) must be written to tolerate the file changing between thestatand the follow-up operation — or better, open the file first andstatthe filehandle.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
lstat— likestatbut does not follow symlinks; reports on the link itself-Xfile-test operators (-e,-f,-r,-w,-x, …) — built on top of the same stat buffer; share the_cache withstatandlstatchmod— change the permission bits reported in field 2 (mode)chown— change theuidandgidreported in fields 4 and 5File::stat— named accessors ($sb->size,$sb->mtime, …) over the same 13-field list;use File::statoverridesstatin the current scopeFcntl—:modetag exports theS_I*constants andS_IS*helpers for decoding field 2