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

I would like to "localize" the default file handle so that it is automatically restored when I exit a block. Something like:
open(my $fh, ...); my $OLDFH; { $OLDFH = select($fh); print ...; ... } select($OLDFH);
except that select($OLDFH) will always get executed when control leaves the inner block (exception, return, etc.)

What's a good way to do this? eval works for catching exceptions. Is there a way to do this with local() ?

Would creating an object whose DESTROY method restores the default handle work?

Replies are listed 'Best First'.
Re: can the default file handle be localized?
by ikegami (Patriarch) on Mar 12, 2009 at 21:27 UTC
    use Sub::ScopeFinalizer qw( scope_finalizer ); { my $old_fh = select($fh); my $sentry = scope_finalizer { select($old_fh); }; ... }

    Sub::ScopeFinalizer

        The OP wants the file handle to be restored automatically on scope exit. The linked node does not provide a means of doing so.

        In fact, Scope::Finalizer could have been used in that post too.

        use Sub::ScopeFinalizer qw( scope_finalizer ); { open(my $old_stdout, '>&', *STDOUT) or die; my $sentry = scope_finalizer { close(STDOUT); open(STDOUT, '>&', $old_stdout) or die; }; close(STDOUT); open(STDOUT, '>', $file) or die; ... }

        The only reason I didn't is that "..." is a call to system, and that doesn't die or otherwise exit the block.

        Update: I missed it since the point of the linked post was to avoid using local *STDOUT in the circumstances of that thread, but local *STDOUT is a simpler alternative to using select + scope_finalizer:

        { local *STDOUT = $OLDFH; ... }
Re: can the default file handle be localized?
by perl5ever (Pilgrim) on Mar 12, 2009 at 22:15 UTC
    Ok - the default file handle can't be localized, but the symbol STDOUT can be. So if you know the name of the current default file handle then you can do what I want with local().

    Thanks!