Copying Filehandles (Perl Cookbook, 2nd Edition)

## 7.10. Copying Filehandles

### 7.10.1. Problem

You want a copy of a filehandle.

### 7.10.2. Solution

To create an alias for a named filehandle, say:

>     *ALIAS = *ORIGINAL;

Use `open` with the `&` file access mode to create an independent copy of the file descriptor for that filehandle:

>     open(OUTCOPY, ">&STDOUT")        or die "Couldn't dup STDOUT: $!";
>     open(INCOPY,  "<&STDIN")         or die "Couldn't dup STDIN : $!";

Use `open` with the `&=` mode to create an alias for that filehandle or file descriptor:

>     open(OUTALIAS, ">&=STDOUT")      or die "Couldn't alias STDOUT: $!";
>     open(INALIAS,  "<&=STDIN")       or die "Couldn't alias STDIN : $!";
>     open(BYNUMBER, ">&=5")           or die "Couldn't alias file descriptor 5: $!";

With other types of filehandles (typeglobs, objects), use the same technique with a three-argument `open`:

>     open(my $copy, "<&",  $original) or die "Couldn't alias original: $!";
>     open(my $copy, "<&=", $original) or die "Couldn't alias original: $!";

### 7.10.3. Discussion

If you create an alias for a filehandle with typeglobs, only one Perl I/O object is still being accessed. If you close one of these aliased filehandles, the I/O object is closed. Any further attempt to use a copy of that filehandle fails, silently by default or, if you have warnings enabled, with the warning "`print` `on` `closed` `filehandle`". When alternating access through aliased filehandles, writes work as you'd expect because there are no duplicated stdio data structures to get out of sync.

If you create a copy of a file descriptor with `open(COPY, ">&HANDLE")`, you're really calling the dup(2) syscall. You get two independent file descriptors whose file position, locks, and flags are shared, but which have independent stdio buffers. Closing one filehandle doesn't affect its copy. Simultaneously accessing the file through both filehandles is a recipe for disaster. Instead, this technique is normally used to save and restore `STDOUT` and `STDERR`:

>     # take copies of the file descriptors
>     open(OLDOUT, ">&STDOUT");
>     open(OLDERR, ">&STDERR");

>     # redirect stdout and stderr
>     open(STDOUT, "> /tmp/program.out")  or die "Can't redirect stdout: $!";
>     open(STDERR, ">&STDOUT")            or die "Can't dup stdout: $!";

>     # run the program
>     system($joe_random_program);

>     # close the redirected filehandles
>     close(STDOUT)                       or die "Can't close STDOUT: $!";
>     close(STDERR)                       or die "Can't close STDERR: $!";

>     # restore stdout and stderr
>     open(STDERR, ">&OLDERR")            or die "Can't restore stderr: $!";
>     open(STDOUT, ">&OLDOUT")            or die "Can't restore stdout: $!";

>     # avoid leaks by closing the independent copies
>     close(OLDOUT)                       or die "Can't close OLDOUT: $!";
>     close(OLDERR)                       or die "Can't close OLDERR: $!";

If you create an alias for a file descriptor using `open(ALIAS, ">&=HANDLE")`, you're really calling the fdopen(3) function from the stdio library or its equivalent. You get a single file descriptor with two stdio buffers accessed through two filehandles. Closing one filehandle closes the file descriptor of any aliases, but not their filehandles—if you tried to `print` to a filehandle whose alias had been `close` d, Perl wouldn't give a "`print` `on` `closed` `filehandle`" warning, even though the `print` failed. In short, accessing the file through both filehandles is also a recipe for disaster. This is really used only to open a file descriptor by number. See Recipe 7.9 for more information on this.

### 7.10.4. See Also

The `open` function in perlfunc(1) and in Chapter 29 of Programming Perl; your system's dup(2) manpage

Copyright © 2003 O'Reilly & Associates. All rights reserved.