Recipe 7.9 Opening and Closing File Descriptors by Number

7.9.1 Problem

You know which file descriptors you'd like to do I/O on, but Perl requires filehandles, not descriptor numbers.

7.9.2 Solution

To open the file descriptor, supply open with "<&=" or "<&" as the part of the file access mode, combined with a directional arrow:

open(FH, "<&=", $FDNUM)       # open FH to the descriptor itself
open(FH, "<&",  $FDNUM);      # open FH to a copy of the descriptor

Or use the IO::Handle module's new_from_fd class method:

use IO::Handle;
$fh = IO::Handle->new_from_fd($FDNUM, "r");

To close a file descriptor by number, either use the POSIX::close function or open it first as shown previously.

7.9.3 Discussion

Occasionally you have a file descriptor but no filehandle. Perl's I/O system uses filehandles instead of file descriptors, so you have to make a new filehandle from an already open file descriptor. The "<&", ">&", and "+<&" access modes to open do this for reading, writing, and updating, respectively. Adding an equals sign to thesemaking them "<&=", ">&=", and "+<&="is more parsimonious of file descriptors and nearly always what you want. That's because the underlying implementation of Perl's open statement uses only a C-level fdopen(3) function from the C library, not a dup2(2) syscall that calls the kernel.

The new_from_fd IO::Handle object method is equivalent to:

use IO::Handle;

$fh = new IO::Handle;
$fh->fdopen($FDNUM, "r");            # open fd 3 for reading

Here's how you'd open file descriptors that the MH mail system feeds its child processes. It identifies them in the environment variable MHCONTEXTFD:

open(MHCONTEXT, "<&=", $fd)   or die "couldn't fdopen $fd: $!";
# after processing
close(MHCONTEXT)              or die "couldn't close context file: $!";

Closing a file descriptor by number is even rarer. If you've already opened a filehandle for the file descriptor you want to close, simply use Perl's close function on the filehandle. If don't have a filehandle for that file descriptor, the POSIX::close function closes a file descriptor by number:

use POSIX;

POSIX::close(3);              # close fd 3

7.9.4 See Also

The open function in perlfunc(1) and in Chapter 29 of Programming Perl; the documentation for the standard POSIX and IO::Handle modules (also in Chapter 32 of Programming Perl); your system's fdopen(3) manpages