fileno#
Return the OS-level file descriptor number behind a filehandle.
fileno looks past Perl’s buffered filehandle abstraction and gives
you the raw integer descriptor the kernel uses. It is the bridge
between Perl I/O and system calls that speak descriptors directly —
select, POSIX::dup2, fcntl, or
anything in IO::Poll / IO::Select. On a directory handle it asks
the same question against dirfd(3), which not every platform
provides.
Synopsis#
fileno FILEHANDLE
fileno DIRHANDLE
fileno EXPR # EXPR evaluated as an indirect handle
What you get back#
An integer
>= 0— the OS file descriptor — for a normal open handle backed by a real kernel object.-1when the handle is open but has no real descriptor. This is what you get for in-memory handles created byopenwith a scalar reference as the third argument (open my $fh, ">", \$buf).undefwhen the handle is closed, never opened, or — on a directory handle — when the platform lacksdirfd(3). In the dirhandle case$!is set.
The three return classes matter. Code that checks fileno($fh) for
truth conflates “no such fd” with “fd number 0” (STDIN). Always
compare explicitly:
my $fd = fileno $fh;
die "handle not open" unless defined $fd;
die "handle has no real fd" if $fd == -1;
Global state it touches#
$!— set whenfilenoon a directory handle fails because the platform has nodirfd(3)equivalent.
fileno does not read or write any other I/O globals. It does not
flush, it does not seek, it does not change the currently selected
handle.
Examples#
The common case — turn a Perl filehandle into the fd number a system call wants:
open my $fh, "<", "/etc/hostname" or die $!;
print fileno $fh, "\n"; # e.g. "3"
Standard handles always have fixed descriptors 0, 1, 2:
print fileno STDIN, "\n"; # 0
print fileno STDOUT, "\n"; # 1
print fileno STDERR, "\n"; # 2
Check whether two handles are duplicates of the same underlying
descriptor (the idiom from the upstream POD, adjusted for the -1
case):
if (fileno($this) != -1 && fileno($this) == fileno($that)) {
print "\$this and \$that are dups\n";
} elsif (fileno($this) != -1 && fileno($that) != -1) {
print "\$this and \$that have different "
. "underlying file descriptors\n";
} else {
print "at least one handle has no real file descriptor\n";
}
In-memory handles have no kernel object, so fileno returns -1:
my $buf = "";
open my $mh, ">", \$buf or die $!;
print fileno $mh, "\n"; # -1
Build a descriptor bitmap for select — the textbook use
for fileno:
my $rin = "";
vec($rin, fileno($sock), 1) = 1;
vec($rin, fileno(STDIN), 1) = 1;
my $n = select(my $rout = $rin, undef, undef, 5.0);
Directory handles, where the platform supports dirfd(3):
opendir my $dh, "." or die $!;
my $dfd = fileno $dh;
if (defined $dfd) {
# use with fstat, openat, fchdir, ...
} else {
warn "no dirfd on this platform: $!";
}
Edge cases#
Closed handle: returns
undef. No warning underuse warnings—filenois deliberately quiet so it can be used as a probe.Never-opened bareword:
fileno NOSUCHreturnsundef; strict mode will refuse the bareword at compile time unless it’s declared.In-memory scalar handles: return
-1, notundef. Treating-1as “open but unusable for system calls” is the intended contract — the handle itself still works forprint,readline, etc.fileno(-1)trap: an explicitif (fileno $fh) { ... }is a bug waiting to happen:fd 0is STDIN. Usedefinedand compare against-1explicitly.Indirect filehandle via expression: if
FILEHANDLEis any expression other than a bareword or simple scalar, its value is taken as an indirect handle name (a string), not as a handle object. To pass a handle held in a data structure, dereference first:fileno $handles[0]; # indirect: uses the string fileno ${ \$handles[0] }; # still wrong fileno $handles[0]->fileno; # wrong: calling a method on "" my $fh = $handles[0]; fileno $fh; # right
Directory handle on platforms without
dirfd(3): returnsundefand sets$!. Linux hasdirfd(3), so on pperl’s supported targets this path is not exercised.Tied handles:
filenocalls the tie class’sFILENOmethod if defined; otherwise returnsundef. The tied class is responsible for returning a sensible value (-1for “no fd” is the convention).Dup’d handles: two handles opened with
openfrom the same underlying fd (e.g.open my $copy, ">&", $orig) return the new descriptor, not the original — the dup created a fresh fd.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
open— creates the filehandles thatfilenoinspects; the>&and<&=modes take descriptor numbers that round-trip throughfilenoopendir— source of directory handles for the dirhandle form offilenoselect— the four-argument form consumes bitmaps built fromfilenovaluesbinmode— works on the PerlIO layer above the fd;filenoreaches beneath it