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

My script calls a sub, Pod::Select::podselect(), which writes the pod sections found in files to a named file or to STDOUT (default).

I want to collect those pod sections in a hash, %podstrings. Is there a way to redirect that output back into my script? Something more elegant than writing to a tempfile and then reading that file back into my hash?

If podselect() returned the string, it would be easy - but it does not, and I don't wish to hack it.
#!/usr/bin/perl -w use strict; use File::Find; use File::Slurp; use Pod::Select; my $dir = "h:/temp/TestAppNotes/Pod/"; my %podstrings; find ( sub { return if -d; ### I would like to assign ### $filestrings{$File::Find::name} = podselect $File::Find::name; + my $tmpfile = "$dir/tmpfile.txt"; podselect {-output => $tmpfile}, $File::Find::name; if (-s $tmpfile) { $podstrings{$File::Find::name} = scalar read_file($tmpfile) } }, $dir); for (keys %podstrings) { printf "%s %d\n", $_, -s $_; } __END__
Rudif

Replies are listed 'Best First'.
Re: Could I redirect stdout back into my script?
by stephen (Priest) on Apr 22, 2001 at 03:53 UTC
    If you have 5.004 or greater, you can have any section of code "print" to a scalar using the capabilities of IO::Scalar. For example:
    require 5.004; use strict; use IO::Scalar; my $output_string = ''; tie *STDOUT, 'IO::Scalar', \$output_string; &stdout_sub(); untie *STDOUT; sub stdout_sub { print "This will not print to screen.\n"; }
    This will preserve whatever stdout_sub() printed in the string $output_string.

    stephen

      If you want the old STDOUT back, You might want to wrap the code in a block and localize STDOUT:
      { my $output_string = ''; local *STDOUT; tie *STDOUT, 'IO::Scalar', \$output_string; stdout_sub(); }
      Update: My mistake. The untie does seem to take care of restoring the old STDOUT.
        Not a bad idea, but as far as I can tell, it's not necessary. The 'untie *STDOUT' restores the original STDOUT.

        stephen

Re: Could I redirect stdout back into my script?
by Masem (Monsignor) on Apr 22, 2001 at 03:24 UTC
    While you could use pipes for this, the Pod::Parser piping it's output to your script, the same process cannot be on both ends of the pipe. (See the 'open' docs on PM or at perldoc.com). I would suspect that this means that your reader script can be made a child of the parent process, and thus be the pipe recipent. Again, the open docs give several alternatives to do this.

    Given what might be invovled, the temporary file might be the better idea...


    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: Could I redirect stdout back into my script?
by BrotherAde (Pilgrim) on Apr 22, 2001 at 03:53 UTC
Re: Could I redirect stdout back into my script?
by Rudif (Hermit) on Apr 24, 2001 at 01:47 UTC
    Thanks to all who contributed.

    I tried stephen's solution and it works nicely (using 5.6.0).

    It is a tad faster than my tempfile solution (in the test shown below, 8% faster). And it looks more Perlish.

    Rudif
    #!/usr/bin/perl -w use strict; use File::Find; use File::Path; use File::Slurp; use Pod::Select; use IO::Scalar; use Benchmark; my $dir = "c:/perl/lib/Pod"; my %podstrings; timethese(10, { 'Tmpfile' => sub { %podstrings = (); findTmpfile(); # printf "%d\n", scalar keys %podstrings; }, 'TieStdout' => sub { %podstrings = (); findTieStdout(); # printf "%d\n", scalar keys %podstrings; }, }); sub findTmpfile { find ( sub { return if -d; my $tmpfile = "$dir/tmpfile.txt"; return if $File::Find::name eq $tmpfile; podselect {-output => $tmpfile}, $File::Find::name; if (-s $tmpfile) { $podstrings{$File::Find::name} = scalar read_file($tmpfile +); } unlink $tmpfile if -f $tmpfile; }, $dir); } sub findTieStdout { find ( sub { return if -d; my $output_string = ''; tie *STDOUT, 'IO::Scalar', \$output_string; podselect $File::Find::name; untie *STDOUT; if ($output_string) { $podstrings{$File::Find::name} = $output_string; } }, $dir); } __END__ Benchmark: timing 10 iterations of Tmpfile, findTieStdout... Tmpfile: 123 wallclock secs (120.08 usr + 2.71 sys = 122.80 CPU) @ + 0.08/s (n=10) TieStdout: 103 wallclock secs (102.45 usr + 0.82 sys = 103.27 CPU) @ + 0.10/s (n=10)