2

I am writing a Perl script where I read files containing section Perl code and non Perl data.

After processing the files I write them to a temporary files (generated scripts) which is then executed using an eval command. I don't want to run the generated script separately as I need to use the variables in the main script to be interpolated in the generated scripts.

I need to redirect the output of the eval command to a file. Any suggestion on how to achieve this?

Steps in the script:

  1. READ_FILE

  2. Process file

  3. Write back with temp file name

  4. Read temp file (my $file_name = read_file('temp_file_name'))

  5. eval (eval $file_name)

Appreciate the help.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Arthes
  • 79
  • 1
  • 8
  • Is the output going to STDOUT? – simbabque May 30 '17 at 17:42
  • Yes. It is currently printed on STDOUT. – Arthes May 30 '17 at 17:43
  • Then you can use Capture::Tiny, put it in a variable and then write to a file from there. There are a couple of good answers around. I'll find a duplicate target. – simbabque May 30 '17 at 17:44
  • https://stackoverflow.com/a/3511098/1331451 is basic, I don't think it works as a canonical. https://stackoverflow.com/a/8781408/1331451 is way better, but not the accepted answer so I wouldn't want to close with that. I'll write a new one for the time being. – simbabque May 30 '17 at 17:47
  • Why not just `open` a file on `STDOUT`? – Borodin May 30 '17 at 18:07

3 Answers3

7

You can use capture_stdout from Capture::Tiny to grab the output of your eval.

use strict;
use warnings;
use Capture::Tiny 'capture_stdout';

my $stdout = capture_stdout {
    eval q{print "Hello World!\n";};
};

open my $fh, '>', 'foo.txt' or die $!;
print $fh $stdout;
simbabque
  • 53,749
  • 8
  • 73
  • 136
6

This can be done without any additional modules

use strict;
use warnings;

open my $fh, '>', 'foo.txt' or die $!;
my $old_fh = select $fh;

eval q{ print "Hello World!\n"; };

select $old_fh;
Borodin
  • 126,100
  • 9
  • 70
  • 144
0

TLDR Answer

use Capture::Tiny; with capture_merged() or capture(). You may use capture_stdout() if you like it as a shortcut.

Output? Which output stream? STDOUT or STDERR?

According to Perl, output can be in the form of:

  • STDOUT — Typically caused by print(), etc., statements.
  • STDERR — Typically caused by warn(), etc., statements.

You can use Capture::Tiny to get STDOUT and STDERR merged:

my ($merged,  @result) = capture_merged { eval $codetoeval };

Or, you can use Capture:Tiny to get them separated:

my ($stdout, $stderr, @result) = capture { eval $codetoeval };

You also have the option of capture_stdout() and capture_stderr() if you only want those forms of output. If you only have print() statements, then capture() and capture_stdout() will give the same results.

Complete Demo

use Capture::Tiny ':all';
my $codetoeval = 'print "Hello, World!";';
my ($merged,  @result) = capture_merged { eval $codetoeval };
die "Merge Fail" if !@result;
print("Output : " . $merged);
open my $fh, '>', 'foo.txt' or die $!;
print $fh $stdout;

Full Working Online Demo at IDEOne

Output: Hello, World!

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133