3

I have already defined a bunch of functions which do a lot of work and have a bunch of print statements. They can be called like so to build an html page.

print_A()
print_B()
print_C()

Now, I want to call these functions and store the contents of these print statements into one main variable. One way is to rewrite these functions so they return a string with their contents (instead of printing)

my $var = "";
$var = $var . store_A();
$var = $var . store_B();
$var = $var . store_C();

But I want to do this without modifying or rewriting the functions. I don't want to redefine these functions with such a minor change (there are hundreds of these functions in the program).

Is there a shorter and faster way to do this in perl?

Yasir
  • 77
  • 2
  • 5
  • 4
    This is a really poor way to build HTML for webpages. Consider an existing web framework such as `catalyst` or `mojolicious`. At the least use a templating system such as Template Toolkit. – jordanm Sep 17 '15 at 14:47
  • Also note that in Perl 5.22 the CGI module is not in core any more. – simbabque Sep 17 '15 at 15:21
  • 1
    http://stackoverflow.com/a/3508679, http://stackoverflow.com/a/1534952, http://stackoverflow.com/q/32576886 – mob Sep 17 '15 at 15:50

3 Answers3

11

One way is to use select to redirect STDOUT to a scalar variable:

use warnings;
use strict;

my $out;
open my $fh, '>', \$out;
my $old_stdout = select $fh;
s1();
s2();
select $old_stdout;
close $fh;

print "start\n";
print $out;
print "end\n";

sub s1 {print "s1\n"}
sub s2 {print "s2\n"}

Prints out:

start
s1
s2
end
toolic
  • 57,801
  • 17
  • 75
  • 117
1

Depending on just what these functions do, you may be able to run them in a subprocess and capture their output:

my $pid = open(PIPE, "-|");
if (0 == $pid) {
    # Child
    print_A();
    print_B();
    print_C();
    exit(0);
}
else {
    my $var = "";
    while(<PIPE>) {
       $var .= $_;
    }
    close(PIPE);
}

You'll have to evaluate whether it's safe to move these function calls into a subprocess. If one of these functions changes the process's global state--for example, if it modifies a global variable--then that change will be confined to the child process, and won't happen in the original script process.

Kenster
  • 23,465
  • 21
  • 80
  • 106
0

You can also use IO::Scalar to tie a variable to STDOUT.

use IO::Scalar;

my $output_str;
tie *STDOUT, 'IO::Scalar', \$output_str;
print "Hel", "lo, ";
print "world!\n";

untie *STDOUT;
print "output_str is $output_str\n";

# prints
# output_str is Hello, world!

Not effectively different from @toolic's answer though.

Kevin G.
  • 1,424
  • 1
  • 13
  • 22