Can Perl redirect STDOUT to file AND to command window?

Discussion in 'Perl Misc' started by rcm228@gmail.com, Nov 29, 2005.

  1. Guest

    I have done standard Perl STDOUT redirection to a pipe and to a file,
    however, I have been searching for a way to redirect STDOUT to a file
    and to the command window at the same time. So far, no luck - is this
    possible?

    Ryan
     
    , Nov 29, 2005
    #1
    1. Advertising

  2. Guest

    wrote:
    > I have been searching for a way to redirect STDOUT to a file and to
    > the command window at the same time. So far, no luck - is this possible?


    Sure. use IO::Tee (http://search.cpan.org/~kenshan/IO-Tee-0.64/Tee.pm)

    Or, if you want to get REALLY cool, use Log::Dispatch and attach
    handlers for file and screen (and you can fire the handlers based on
    the log level of the message, so you can fire one or both handlers
    based on the level you stipulate). I use Log::Dispatch for ALL of my
    process messages (I rarely use "print" statements except for trivial
    code).
     
    , Nov 29, 2005
    #2
    1. Advertising

  3. writes:

    > I have done standard Perl STDOUT redirection to a pipe and to a file,
    > however, I have been searching for a way to redirect STDOUT to a file
    > and to the command window at the same time. So far, no luck - is this
    > possible?


    If you're on a *nix, "man tee".

    sherm--

    --
    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org
     
    Sherm Pendley, Nov 29, 2005
    #3
  4. Guest

    Unfortunately, I am on windows (else I wouldnt be here ;)

    My situation is a bit complex and requires me to do all the redirection
    within the script, so I can't get away with this either:

    perl my_script.pl | tee out.txt

    R
     
    , Nov 29, 2005
    #4
  5. Guest

    wrote:
    > Or, if you want to get REALLY cool, use Log::Dispatch and attach
    > handlers for file and screen...


    Here's an example of how to do this. Log::Dispatch is really a great
    way to handle process messages (and you can attach other methods if you
    wish - it can send you e-mail, or log to XML files or to databases)...

    #!/usr/bin/perl
    use strict; use warnings;

    use Log::Dispatch::Screen;
    use Log::Dispatch::File;

    my $log = Log::Dispatch -> new; #This is the logger

    #Logging method for terminal output. Fires at 'debug' or higher
    $log ->add( Log::Dispatch::Screen ->new(
    name => 'screen',
    min_level => 'debug',
    stderr => 0, )
    );
    #Logging method for file output. Fires at 'info' or higher
    $log ->add( Log::Dispatch::File ->new(
    name => 'file',
    min_level => 'info',
    filename => '/tmp/whatever.log',
    mode => 'append' )
    );

    ### Now the logging methods are set up. We can invoke the logger
    ### by passing it a message at a particular urgency level, namely:
    ### debug info notice warning error critical alert emergency
    ### The logger will fire ANY and ALL methods which are defined as
    ### equal to or less than the urgency level we stipulate.

    $log -> debug("This message goes to the screen only\n");
    $log -> info("This message goes to BOTH screen and file.\n");

    $log -> log_to(name => 'file',
    level => 'info',
    message => "Force message to go to file ONLY\n");

    __END__

    # Never use 'print()' again!
     
    , Nov 29, 2005
    #5
  6. Guest

    wrote:
    > Here's an example of how to do this. Log::Dispatch is really a great
    > way to handle process messages...


    But, wait, there's more! If you use the Log::Dispatch module in the
    next 30 minutes, you will get callback capability at NO ADDITIONAL
    COST! That's right - a billion dollar value is yours FREE!

    Are you tired of having to fuss with linefeeds on your output messages?
    Define a callback! Do you want to timestamp each line that you write
    to your logfile (but not bother to show the timestamp on STDOUT
    messages? Define a callback! For example:

    my $add_lf = sub { my %p = @_; "$p{'message'}\n"};
    my $add_timestamp = sub { my %p = @_;
    sprintf "%s - %s", scalar(localtime),
    $p{'message'}; };

    OK, now you've defined two callbacks (one to add linefeeds, one to add
    timestamps). Assuming that you want to add linefeeds to every single
    thing that you output, you would define your logger to always use the
    $add_lf callback:

    $log = Log::Dispatch->new ( callbacks => $add_lf );

    But you only want to call the timestamp-er on the 'file' method, so you
    would define that method like this:
    $log ->add( Log::Dispatch::File ->new(
    name => 'file',
    min_level => 'info',
    filename => '/tmp/whatever.log',
    callbacks => $add_timestamp,
    mode => 'append' )
    );

    Now you can log even multiple lines, such as this:

    $log->debug('line 1', 'line 2', 'line 3');

    And it will automatically add linefeeds to each line, and it will
    timestamp each line (but only in the file, not on the terminal).

    Call CPAN now - webservers are standing by to take your order!
     
    , Nov 29, 2005
    #6
  7. Guest

    Thanks for the start, IO::Tee works well like this:

    use strict;
    use IO::Tee;

    my $tee = IO::Tee->new(\*STDOUT,">out.txt");
    print $tee "test\n";

    However, I am looking for something like this where I dont need to
    print to the $tee handle:

    use strict;
    use IO::Tee;

    my $tee = IO::Tee->new(\*STDOUT,">out.txt");
    open(STDOUT, ">&$tee");
    print "test\n";

    This creates out.txt and prints "test" to the screen but not to out.txt

    Do I need to use tie() ?

    tie(*STDOUT, "mypackage");

    R
     
    , Nov 29, 2005
    #7
  8. Guest

    wrote:
    > However, I am looking for something like this where I dont need to
    > print to the $tee handle:


    Hmmm. I don't know if you can do this. 'print' (by default) goes to
    STDOUT. But you want to redefine STDOUT as a tee that goes to a file
    and... STDOUT. But STDOUT is now a tee that goes to a file and...
    STDOUT. This goes on forever.
     
    , Nov 29, 2005
    #8
  9. Guest

    Yeah...I got stuck in that loop myself, my watchdog kicked....bummer, I
    guess the consensus for this thread is "no" unless you want to be
    explicit about the handle.

    Thanks for the help...

    R
     
    , Nov 29, 2005
    #9
  10. Guest

    wrote:
    > Thanks for the start, IO::Tee works well like this:
    >
    > use strict;
    > use IO::Tee;
    >
    > my $tee = IO::Tee->new(\*STDOUT,">out.txt");
    > print $tee "test\n";
    >
    > However, I am looking for something like this where I dont need to
    > print to the $tee handle:


    How about just selecting $tee so that it becomes the default output handle?

    select $tee;

    >
    > use strict;
    > use IO::Tee;
    >
    > my $tee = IO::Tee->new(\*STDOUT,">out.txt");
    > open(STDOUT, ">&$tee");


    Always check the success of your open.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Nov 29, 2005
    #10
  11. Guest

    >select $tee;

    BRILLIANT!

    I dont know how that was missed...thanks for the help.
     
    , Nov 30, 2005
    #11
  12. Guest

    PG,

    I don't want to go into too much gory detail, but basically my module
    is for concurrent scripting with a simple IPC interface that works via
    C++, users of the module don't know that I am redirecting their output
    to a file and to the cmd window ;)

    R
     
    , Nov 30, 2005
    #12
  13. Guest

    **** SUMMARY **** (for those on the Google quest)

    use strict;
    use IO::Tee;

    my $tee = IO::Tee->new(\*STDOUT,">out.txt");
    select $tee;

    print "Hello World\n"; # will print Hello World to both cmd window and
    ../out.txt

    R
     
    , Nov 30, 2005
    #13
  14. Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > wrote:
    > > However, I am looking for something like this where I dont need to
    > > print to the $tee handle:

    >
    > Hmmm. I don't know if you can do this. 'print' (by default) goes to
    > STDOUT.


    It goes to the filehandle chosen by select(). The default is STDOUT.

    > But you want to redefine STDOUT as a tee that goes to a file
    > and... STDOUT. But STDOUT is now a tee that goes to a file and...
    > STDOUT. This goes on forever.


    One could tie STDOUT to something that writes to the file and to
    what STDOUT used to be before the tie. Using the IO::Tee module:

    use IO::Tee;

    my $file;
    open $file, '>', $_ or die "Can't create '$_': $!" for '/tmp/x';
    my $tee = IO::Tee->new( \ *STDOUT, $file);
    select $tee;

    print "$_\n" for qw( hihi haha hoho);

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Nov 30, 2005
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Elad
    Replies:
    0
    Views:
    435
  2. Jef Driesen

    Can I redirect stdout to a file AND the console.

    Jef Driesen, Nov 23, 2007, in forum: C Programming
    Replies:
    10
    Views:
    1,506
    Jack Klein
    Nov 25, 2007
  3. Sal
    Replies:
    1
    Views:
    997
  4. Replies:
    2
    Views:
    168
    Tad McClellan
    Mar 26, 2005
  5. it_says_BALLS_on_your forehead
    Replies:
    2
    Views:
    293
    Joe Smith
    Jan 10, 2006
Loading...

Share This Page