isotope has asked for the wisdom of the Perl Monks concerning the following question:

This is related to my earlier post, Teeing STDOUT and STDERR to files using filehandle references, from about a month ago.
I'm redirecting STDOUT and STDERR to files with code similar (but with more function calls in the way) to this:
$this->{'stdout_log'} = \*FH_STDOUT; # These files have already been o +pened. $this->{'stderr_log'} = \*FH_STDERR; # Save the previous filehandles for STDOUT and STDERR so we # can restore them when we're done. $this->{'_stdout'} = \*STDOUT; $this->{'_stderr'} = \*STDERR; # Set the new filehandles for STDOUT and STDERR *STDOUT = $this->{'stdout_log'}; *STDERR = $this->{'stderr_log'};
Later, I try to restore STDOUT and STDERR before I close the logfiles:
if(defined($this->{'_stdout'})) { *STDOUT = $this->{'_stdout'}; print STDOUT "STDOUT restored\n"; # Filehandle explicitly specifie +d for debugging only... undef($this->{'_stdout'}); } if(defined($this->{'_stderr'})) { *STDERR = $this->{'_stderr'}; print STDERR "STDERR restored\n"; undef($this->{'_stderr'}); }
I successfully log STDOUT/ERR to a file, but when I attempt to restore them later, the if blocks evaluate, but the print statements still go to the logfiles, instead of the TTY. Following that, of course, when I close the files and attempt to print to STDOUT and STDERR, I get:
print() on closed filehandle main::STDOUT at FSLAMTest.pm line 312.
It would seem that my attempt to preserve the original STDOUT and STDERR is not successful. Any suggestions? TIA.

--isotope
http://www.skylab.org/~isotope/

Replies are listed 'Best First'.
Re: Restoring STDOUT and STDERR after having redirected them to files
by isotope (Deacon) on Jan 13, 2001 at 00:19 UTC
    chipmunk accurately identified the source of my problem. I had thought I was copying the filehandles, but I was actually dup'ing globs, so I was stomping the filehandle value anyway. Unfortunately, the fileno approach is only useful if I use it everywhere in my code, which I didn't, for other reasons. I did, however, manage to put together a solution that works exactly as desired, massaging things into the approach suggested in perlfunc:open:
    # Save the previous filehandles for STDOUT and STDERR so we # can restore them when we're done. local *REAL_STDOUT; local *REAL_STDERR; open(REAL_STDOUT, ">&STDOUT"); open(REAL_STDERR, ">&STDERR"); $this->{'_stdout'} = *REAL_STDOUT; $this->{'_stderr'} = *REAL_STDERR; # Set the new filehandles for STDOUT and STDERR local *STDOUT_LOG; local *STDERR_LOG; *STDOUT_LOG = $this->{'stdout_log'}; *STDERR_LOG = $this->{'stderr_log'}; open(STDOUT, ">&STDOUT_LOG"); open(STDERR, ">&STDERR_LOG");
    I can restore STDOUT and STDERR later with this code:
    if(defined($this->{'_stdout'})) { local *REAL_STDOUT; *REAL_STDOUT = $this->{'_stdout'}; open(STDOUT, ">&REAL_STDOUT") or warn "Couldn't restore STDOUT: $! +"; print STDOUT "STDOUT restored\n"; undef($this->{'_stdout'}); } if(defined($this->{'_stderr'})) { local *REAL_STDERR; *REAL_STDERR = $this->{'_stderr'}; open(STDERR, ">&REAL_STDERR") or warn "Couldn't restore STDERR: $! +"; print STDOUT "(STDERR restored)\n"; print STDERR "STDERR restored\n"; undef($this->{'_stderr'}); }
    Everything's happy now.

    --isotope
    http://www.skylab.org/~isotope/
Re: Restoring STDOUT and STDERR after having redirected them to files
by chipmunk (Parson) on Jan 12, 2001 at 22:46 UTC
    Have you reviewed the examples in the documentation for open on saving and restoring STDOUT and STDERR? I suspect that your glob assignments are overwriting each other, rather than saving the old values.
        Ah... But, reading a little further down in the documentation for open...
        If you specify '<&=N', where N is a number, then Perl will do an equivalent of C's fdopen() of that file descriptor; this is more parsimonious of file descriptors. For example: open(FILEHANDLE, "<&=$fd")
        So, using fileno() on your globs, you can dup your filehandles like in the open example, except with the numbers instead of the names! An updated snippet from your code:
        # restore STDOUT my $fd = fileno($this->{'_stdout'}); open(STDOUT, ">&=$fd"); print STDOUT "STDOUT restored\n";