How can I print to a variable instead of a file, in Perl?

10,470

Solution 1

You can treat a scalar variable as a filehandle by opening it:

open my $fh, '>', \$variable or die "Can't open variable: $!";
print $fh "Treat this filehandle like any other\n";

You can even map stdout or stderr to a scalar:

close STDOUT;
open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";

If you want to split your output or set up a config file to do "interesting" things with your logging, you are better off with Log4Perl as others have suggested.

Solution 2

Do you mean something like IO::Scalar? Lets you write to a variable with filehandle semantics.

Solution 3

If you want to do selective logging where you can control which messages are logged and where they are logged, use Log::Log4perl. That will save you a bunch of time over messing with ties and other black magic.

Solution 4

You can use File::Tee to split a filehandle into multiple output streams.

use File::Tee;
open my $fh, '>', 'logfile.txt' or die $!;
tee( $fh, '>', 'otherlogfile.txt' ) if $condition;
print $fh $current_iteration;   # will also go to otherlogfile.txt 
                                # if $condition was true

Solution 5

Perlfaq5 recommends Tie::FileHandle::Multiplex for printing to multiple files.

The source is very simple and it should be easy to modify with a per-handle filter.

Share:
10,470

Related videos on Youtube

Paul Nathan
Author by

Paul Nathan

Software engineer/craftman/programmer Passion for quality and correctness as exemplified in the continuous improvement/kaizen model. Obsessive about tools and infrastructure Focused on working in Scala/Rust/Lisp/Haskell/OCaml Articulate Lisp - a Common Lisp environment tutorial site. Learn Common Lisp today!

Updated on April 17, 2022

Comments

  • Paul Nathan
    Paul Nathan about 1 month

    How can I print to a variable with Perl?

    I've been working on a program for a while which logs its iterative progress in a highly verbose fashion...

    print $loghandle $some_message;
    

    However, I'd like to also selectively print some of the messages to a different file. Naturally, I could sprinkle the code with...

    print $loghandle $some_message
    print $otherloghandle $some_message
    

    Or rewrite the whole business into a function. Blah.

    What I want to do is do some magic when I open the $loghandle so that when I'm print'ing, I'm actually just doing a sprintfish operation against a variable(call it $current_iteration), so that when I get down to a decision point I can do something like this...

    print $real_log_file $current_iteration;
    print $other_real_log_file $current_iteration if($condition);
    

    I'm fairly sure I've seen something like this somewhere, but I have no idea where it is or where to look.

    edit: File::Tee solves this problem to some extent on *nix, but I run on Windows.

    • Sinan Ünür
      Sinan Ünür over 12 years
    • Sinan Ünür
      Sinan Ünür over 12 years
      @Paul Nathan I linked to brian d foy's answer. Use Log4perl. Express your $condition as a logging level, define the actions. I am not adding this as an answer as I do not have time to check how it works, but I would thoroughly recommend Log4perl based on past experience.
    • Paul Nathan
      Paul Nathan
      Possibly. I'm not trying to tee the actual streams really(though that doesn't matter); it's more setting a variable to act as a destination stream. I'm being lazy and not wanting to rewrite 50-odd logging messages, see. :-)
  • Paul Nathan
    Paul Nathan over 12 years
    I run on Windows(File::Tee doesn't). adding that to the question.
  • Paul Nathan
    Paul Nathan over 12 years
    I think so, but I have the dumb today and don't see how tie actually works here.
  • brian d foy
    brian d foy over 12 years
    You don't need IO::Scalar explicitly. open() by itself works just fine.
  • Paul Nathan
    Paul Nathan over 12 years
    I am amused! And I wasn't sure about the aliasing/referencing args to functions. Thank you!