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

Hi monks,
I am looking for a way to redirect STDOUT (and STDERR also) from system function to a log file and also to the screen. The sample script shown below will redirect the print statement's output to both just fine; however, only system's return value is redirected to both the log and displayed on the screen. Does anyone know of a way to redirect the output from the command (cleartool) that system is passed to both the screen and the log file? I am running my script on Windows XP.

This is my first posting and I am not a perl expert. Your help would be greatly appreciated. Thanks in advance.


use IO::Tee;
my $tee = IO::Tee -> new(">stdout.log", \*STDOUT);
print $tee system("cleartool describe lbtype:MYLABEL");
print $tee "\nThis will print to screen and redirects to file!\n";

  • Comment on How do I redirect outut from system () to a file and also to screen

Replies are listed 'Best First'.
Re: How do I redirect outut from system () to a file and also to screen
by brian_d_foy (Abbot) on May 24, 2005 at 20:36 UTC

    The system() built-in doesn't return the output of the command. Whatever command runs shares the same standard output and standard error as the perl process. Are you sure you aren't seeing the output from "cleartool describe" on the screen?

    Besides that, the tee is only going to work from the Perl program. The system() call won't know anything about it. You can collect the output from the command with the backticks or qx// operator (they're the same thing), then print it to wherever you want to put it.

    The normal advice about collecting standard error involves some unix shell stuff, and I'm not sure how that works on Windows so I'll have to defer to someone else about that. I tend to like IPC::Open3, but I've heard mumblings about people who have had problems with that on Windows.

    --
    brian d foy <brian@stonehenge.com>
      Brian,

      The backticks work fine!! Thanks for your help.

      use IO::Tee;
      my $tee = IO::Tee -> new(">stdout.log", \*STDOUT);

      my $clrout = `cleartool describe lbtype:MYLABEL`;
      print $tee "\n$clrout also prints to screen and redirects to file!\n";
      print $tee "\nThis will print to screen and redirects to file!\n";

        You won't tee your STDERR with backticks, though. All they do is point the command's STDOUT to a string, which is then given back to you. STDERR still goes to the original STDERR, unless you do  `command 2>&1`, which will include the error messages too.

        This seems to work even under Win, even though it's bash syntax.
        Update: as eyepopslikeamosquito already points out below

        This, of course, shoves everything in the same log, which is not optimal - Log::Log4perl is probably your best friend here, and it will do you a ton of good in the future too, once you learn its ways

Re: How do I redirect outut from system () to a file and also to screen
by eyepopslikeamosquito (Archbishop) on May 24, 2005 at 22:07 UTC

    If the command runs quickly:

    my $out = `cmd-to-run 2>&1`; # Should really check command return code via $? special variable here # Then print $out via your $tee here # Note: 2>&1 (to fold stderr into stdout) works fine on Windows XP
    If it is a long-running command and you want feedback while it is running:
    open(my $fh, 'cmd-to-run 2>&1 |') or die "open error: $!"; while (<$fh>) { # print $_ via your $tee here } close($fh) or die "close error: $!";
    And autoflushing stdout ($| = 1;) is prudent in these type of scripts to avoid any intermingling of command stdout and your script's stdout.

Re: How do I redirect outut from system () to a file and also to screen
by Transient (Hermit) on May 24, 2005 at 20:15 UTC
    Unless you are constrained to using system, qx// might be a better choice.
Re: How do I redirect outut from system () to a file and also to screen
by ivancho (Hermit) on May 24, 2005 at 20:23 UTC
    read

    perldoc -f system

    and

    perldoc -q STDERR
Re: How do I redirect outut from system () to a file and also to screen
by nothingmuch (Priest) on May 25, 2005 at 12:06 UTC
    IPC::Run is portable and flexible. I think it should do what you want:
    use IPC::Run qw/run/; use IO::Tee; my $tee = IO::Tee->new(">output.log", \*STDOUT); # called output.log b +ecause it's both stderr and stdout my $printer = sub { print $tee @_ }; # kludge because IO::Tee doesn't +implement the FILENO method my $in = ""; # this data is sent into the command run [qw/cleartool describe lbtype:MYLABEL/], \$in, $printer, $printer;
    I'm not 100% sure this will work on windows since I can't test, but it should be OK.

    IPC::Run will call the anonymous sub in $printer every time there's output on STDOUT or STDERR. That's why it's passed twice. This sub just delegates to tee, which will write the output on STDOUT and the file, like you did before.

    Ideally it would look like

    run [qw/cleartool describe lbtype:MYLABEL/], \$in, $tee, $tee;
    But I think IPC::Run's parameter processing does not recognize $tee as a file handle, since fileno($tee) breaks.

    You can also ask IPC::Run to dup STDERR to STDOUT, by doing something like this (untested):

    run [qw/cleartool describe lbtype:MYLABEL/], ">&", $printer;
    Which is more concise, but doesn't show how flexible IPC::Run is ;-)
    -nuffin
    zz zZ Z Z #!perl
Re: How do I redirect outut from system () to a file and also to screen
by Amar (Sexton) on May 25, 2005 at 12:10 UTC
    If u can use other commands than system()..u may use open() like this:
    open (logHdle, ">C:/path2log.txt"); open (progHdle, "ping somehost|"); while(<progHdle>) { print logHdle $_ ; print STDOUT $_; } close(logHdle); close(progHdle);
    I havent tested the code, but it should work
Re: How do I redirect outut from system () to a file and also to screen
by tcf03 (Deacon) on May 25, 2005 at 13:28 UTC
    I had a similar question a while back in the following node; saving search results to file. I had some good replies. It looks though as your question has been awnsered sufficiently though.
    Ted
    --
    "That which we persist in doing becomes easier, not that the task itself has become easier, but that our ability to perform it has improved."
      --Ralph Waldo Emerson
      Thanks to all for your help!!