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

Is there a better way to restore the STDOUT filehandle than using the dummy filehandle OLDOUT as shown here? Or is this the preferred way?

#!/usr/bin/perl -w $log_file = "logfile"; open(OLDOUT,">&STDOUT"); open(STDOUT, "| tee $log_file") or die "Can't open: $!\n"; print "Testing 1.2.3...\n"; close(STDOUT) or die "Can't close: $!\n"; open(STDOUT,">&OLDOUT"); print "done\n"; close(OLDOUT);
Here's the desired result:
*Write Testing 1.2.3... to STDOUT and log_file *Write done to STDOUT (but NOT log_file)
Thanks. --slojuggler....

Replies are listed 'Best First'.
Re: Is there a better way to restore STDOUT ?
by chromatic (Archbishop) on Jul 14, 2001 at 07:10 UTC
    One use of local. Note the braces:
    print "Should go to stdout.\n"; { local *STDOUT; open(STDOUT, ">afile.txt") or die "Couldn't open afile.txt: $!"; print "Should go to afile.txt\n"; } print "Should go to stdout.\n";
Re: Is there a better way to restore STDOUT ?
by LD2 (Curate) on Jul 14, 2001 at 07:15 UTC
    One way is using select, as premchai21 mentioned. An example of this is:
    $previous_fh = select(STDOUT); #selects STDOUT and saves the selected +filehandle/handle $| = 1; #auto-flushes STDOUT select($previous_fh); # restores the previous filehandle/handle
    Or you could use SelectSaver - which is used to save and restore a selected filehandle. Or follow chromatic's suggestion. :)
      Hi all, Thanks for your help. I've incorporated your suggestions into the following test code.
      #!/usr/bin/perl -w #First example: #Use select to redirect to FILE (which tees to STDOUT) or # to redirect to STDOUT $my_perlhome = "/home/privera/perl"; $log_file = "$my_perlhome/logfile"; $log_file2 = "$my_perlhome/logfile2"; $log_file3 = "$my_perlhome/logfile3"; $log_file4 = "$my_perlhome/logfile4"; $log_file5 = "$my_perlhome/logfile5"; #Flush buffers #$|=1; print "First example: select\n"; open(FILE, "| tee $log_file") or die "Can't open: $!\n"; select (FILE); print "Testing 1.2.3...\n"; close(FILE) or die "Can't close: $!\n"; select (STDOUT); print "done\n"; #Second example: #Uses local (notice braces) print "\nSecond example: local\n"; print "Should go to stdout.\n"; { local *STDOUT; open (STDOUT,"| tee $log_file2") or die "Can't open: $!\n"; print "Should go to second logfile and STDOUT\n"; } print "Should go to stdout.\n"; #Third example: #Uses SelectSaver #Info from perldoc.com: #"A SelectSaver object contains a reference to the file handle that #was selected when it was created. If its new method gets an extra par +ameter, #then that parameter is selected; otherwise, the selected file handle #remains unchanged. # #When a SelectSaver is destroyed, it re-selects the file handle #that was selected when it was created." print "\nThird example: SelectSaver\n"; use FileHandle; use SelectSaver; { my $newfh = new FileHandle("| tee $log_file3") or die "Can't open: $!\n"; my $saver = new SelectSaver($newfh); # <$newfh> is selected print "Should go to third logfile and STDOUT\n"; } # previous handle (STDOUT) is selected print "Should go to stdout.\n"; print "\nFourth example: select multiple\n"; open(FILE, "| tee $log_file4") or die "Can't open: $!\n"; select (FILE); print "This is written to both STDOUT and the fourth logfile\n"; select (STDOUT); print "This is written only to STDOUT\n"; select (FILE); print "This next message is written to both STDOUT and the fourth logf +ile\n"; close(FILE) or die "Can't close: $!\n"; select (STDOUT); print "done\n"; print "\nFifth example: select multiple object oriented\n"; my $newfh = new FileHandle ("| tee $log_file5") or die "Can't open: $! +\n"; select ($newfh); print "This is written to both STDOUT and the fifth logfile\n"; select (STDOUT); print "This is written only to STDOUT\n"; select ($newfh); print "This next message is written to both STDOUT and the fifth logfi +le\n"; close($newfh) or die "Can't close: $!\n"; select (STDOUT); print "done\n";
      Here's a wrinkle I now face. The output from the above code is:
      <privera> 121% select.pl First example: select Testing 1.2.3... done Second example: local Should go to stdout. Should go to second logfile and STDOUT Should go to stdout. Third example: SelectSaver Should go to third logfile and STDOUT Should go to stdout. Fourth example: select multiple This is written only to STDOUT This is written to both STDOUT and the fourth logfile This next message is written to both STDOUT and the fourth logfile done Fifth example: select multiple object oriented This is written only to STDOUT This is written to both STDOUT and the fifth logfile This next message is written to both STDOUT and the fifth logfile done
      Why are the fourth and the fifth examples not written out in the same order as they were programmed? I tried setting $|=1 and setting autoflush to 1 with similar results. I even tried tossing in an extra "sleep 2" in to see if the order would change, but the results were the same. Thanks.
Re: Is there a better way to restore STDOUT ?
by premchai21 (Curate) on Jul 14, 2001 at 06:52 UTC
    See select. Open a new filehandle to the pipe, then select it; select returns the old filehandle, so, if you're absolutely sure that it will be STDOUT, just select(STDOUT) afterwards; if you want to create reusable code, try instead saving select's return value and selecting that later instead.