Recipe 7.19. Opening and Closing File Descriptors by Number
Author: Tom Christiansen & Nathan Torkington
Date: 1999-07-02T01:37:35Z

#

| Chapter 7 File Access |

## 7.19. Opening and Closing File Descriptors by Number

### Problem

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

### Solution

To open the file descriptor, use the `"<&="` or `"<&"` open modes or the IO::Handle module's `fdopen` class method:

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

    use IO::Handle;

    $fh->fdopen($FDNUM, "r");   # open file descriptor 3 for reading

To close one by number, either use the `POSIX::close` function or else first open it as we did previously.

### 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 for an already open file descriptor. The `"<&"`, `">&"`, and `"+<&"` modes to `open` will do this for reading, writing, and updating respectively. Adding an equal sign to these to make `"<&="`, `">&="`, and `"+<&="` is more parsimonious of file descriptors and nearly always what you want to do. That's because it used only a C-level `fdopen` function, not a `dup2` system call.

If you have version 5.004 or better installed, you can use the IO::Handle object method. This is the same as:

    use IO::Handle;
    $fh = IO::Handle->new();

    $fh->fdopen(3, "r");            # open fd 3 for reading

Closing a file descriptor by number is even rarer. The `POSIX::close` function does so directly. If your system doesn't have a working POSIX library but does have a working `syscall` (and your sysadmin has installed the sys/syscall.ph file created with the h2ph translator), you can call the not very portable `syscall` function. It has peculiar parameters and return values: You have to add 0 to numbers and append the empty string (`""`) to strings to coerce them to the right types for C, and the error return value is -1 rather than false as in other Perl calls. Needless to say, use `syscall` only as a last resort.

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

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

If you want to close a descriptor by number, just `open` it first.

### See Also

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

7.18. Printing to Many Filehandles Simultaneously |  | 7.20. Copying Filehandles