6

A very simple question, but I can't easily find an answer.

I want all say in a block to go to a file. But then I want my output to return to STDOUT. How to do that?

my $fh_foo = open "foo.txt", :w;
$*OUT = $fh_foo;
say "Hello, foo! Printing to foo.txt";

$*OUT = ????;
say "This should be printed on the screen";
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Eugene Barsky
  • 5,780
  • 3
  • 17
  • 40
  • 1
    Edited to clarify -- as the title should not just describe the topic or subject you're asking about, but describe the *actual question itself*. – Charles Duffy Nov 15 '17 at 22:10
  • 1
    How would you do it if it weren't $*OUT but some other variable you want to temporarily overwrite? – Holli Nov 15 '17 at 22:37
  • 1
    Maybe glancing at the code in one of the modules I linked to in [this comment](https://stackoverflow.com/questions/47271120/how-to-pipe-a-string-to-process-stdin#comment81525467_47271351) will be helpful. – raiph Nov 15 '17 at 23:16
  • 2
    @CharlesDuffy That's much better, thanks! Holli, nice solution. raiph thanks. – Eugene Barsky Nov 16 '17 at 06:35

1 Answers1

8

The simple answer is to only change it lexically

my $fh-foo = open "foo.txt", :w;
{
  my $*OUT = $fh-foo;
  say "Hello, foo! Printing to foo.txt";
}

say "This should be printed on the screen";
my $fh-foo = open "foo.txt", :w;

with $fh-foo -> $*OUT {
  say "Hello, foo! Printing to foo.txt";
}

say "This should be printed on the screen";

If you have to work around someone else's code you could reopen it the same way it was opened in the first place.

my $fh-foo = open "foo.txt", :w;
$*OUT = $fh-foo;
say "Hello, foo! Printing to foo.txt";

$*OUT = IO::Handle.new( path => IO::Special.new('<STDOUT>') ).open();

say "This should be printed on the screen";
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • Shouldn't the second example use `given` instead of `with`? Because if the block will contain real code, it should error out (pun not intended) rather than be silently skipped. – piojo Nov 16 '17 at 02:38
  • 1
    @Holli Brad's early examples are automatically safe. They reset the old `$*OUT` after the scope, even if the code throws exceptions. That's generally a very good habit. You can't screw it up (for example, if a coworker adds an early `return` to a function). – piojo Nov 16 '17 at 02:40
  • 1
    @piojo I was thinking about having it as `with $fh-foo {…} else -> $failure {…}` – Brad Gilbert Nov 16 '17 at 23:31