http://www.perlmonks.org?node_id=490307

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

Dear Perl Monks:

I want to redirect both STDOUT and Error messages to a file and also display in the screen, when I run a perl script.
I know that using tee.exe will help in gettting this done. But this operation will not return the exit code of the script.
perl -w sample1.pl 2>&1 | tee stdout.txt
So I tried to do this.
perl -w sample1.pl > stdout.txt 2>&1
But it only redirects the STDOUT and error messages to a file (Not printing in the screen).
Does any body know an alternative way of doing this w.o using tee.exe?

------------------- UPDATE -----------------------
Note: I am using a Windows XP/2000 machine!
-----------------------------------------------------
Thanks!

Replies are listed 'Best First'.
Re: Redirecting STDOUT and standard error to file
by Zaxo (Archbishop) on Sep 08, 2005 at 20:50 UTC

    IO::Tee will do what you want. It's a little tricky to "cast" (C-speak) an IO::Tee object to a global handle, but this will do it. Perl 5.8x with PerlIO.

    my $exitcode = do { use IO::Tee; open my $ef, '>>', '/path/to/stderr.txt' or die $!; open my $of, '>>', '/path/to/stdout.txt' or die $!; local *STDERR = *{IO::Tee->new('> /dev/tty', $ef)}; local *STDOUT = *{IO::Tee->new('> /dev/tty', $of)}; warn scalar localtime; print scalar(localtime), "\n"; warn 'Here I am!'; print "Here, too!\n"; system '/loc/of/perl', '/path/to/sample1.pl'; };

    As with any localized global variable, subroutines called from the local scope will honor the local value.

    After Compline,
    Zaxo

Re: Redirecting STDOUT and standard error to file
by jfroebe (Parson) on Sep 08, 2005 at 20:24 UTC

    Hi

    To do so, you would either have to write to STDOUT and to a text file in your sample1.pl OR write a variation of the tee program. Something like:

    sub print_out { my $text = shift; my $FH = shift; print $text; print $FH $text; } print_out "hi there\n";

    Jason L. Froebe

    Team Sybase member

    No one has seen what you have seen, and until that happens, we're all going to think that you're nuts. - Jack O'Neil, Stargate SG-1

Re: Redirecting STDOUT and standard error to file
by eff_i_g (Curate) on Sep 08, 2005 at 20:47 UTC
    #!/usr/bin/perl -w use strict; sub multiprint { for (*FILE, *STDOUT) { print $_ @_; } } open FILE, '>tmp' or die; multiprint('test'); close FILE;

    not sure how to handle the STDERR yet...
Re: Redirecting STDOUT and standard error to file
by davidrw (Prior) on Sep 08, 2005 at 21:01 UTC
    googling for "tee exit code" i found this that works (source):
    (/bin/foo ; echo $? >RES)| tee -a $LOGFILE export ERR=$(cat RES)

    I also found this posting (see also man bash and search for PIPESTATUS) that says that this will work:
    $ cat test #!/bin/bash echo foo sleep 2 echo bar false $ ./test | tee blah foo [.. seconds later..] bar $ echo ${PIPESTATUS[@]} 1 0 # (so ${PIPESTATUS[0]} should give you the return of the first comma +nd).
    But i was unable to get it to work (PIPESTATUS seemed to always have just one element of 0)...

      PIPESTATUS works for me.

      $ uname -s -r FreeBSD 5.4-RELEASE $ bash --version GNU bash, version 2.05b.0(1)-release (i386-portbld-freebsd4.8) Copyright (C) 2002 Free Software Foundation, Inc.

      man bash extract:

      PIPESTATUS
      An array variable (see Arrays below) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command).
Re: Redirecting STDOUT and standard error to file
by sh1tn (Priest) on Sep 08, 2005 at 20:52 UTC
Re: Redirecting STDOUT and standard error to file
by eyepopslikeamosquito (Archbishop) on Sep 08, 2005 at 22:16 UTC

    Back in 1996, Tom Christiansen's celebrated "Csh Programming Considered Harmful" post showed how it can be done even in humble /bin/sh (but not in csh, of course ;-) as follows:

    Consider the pipeline:
    A | B | C
    You want to know the status of C, well, that's easy: it's in $?, or $status in csh. But if you want it from A, you're out of luck -- if you're in the csh, that is. In the Bourne shell, you can get it, although doing so is a bit tricky. Here's something I had to do where I ran dd's stderr into a grep -v pipe to get rid of the records in/out noise, but had to return the dd's exit status, not the grep's:
    device=/dev/rmt8 dd_noise='^[0-9]+\+[0-9]+ records (in|out)$' exec 3>&1 status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) +| egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1` exit $status;

    Update: Please note that the above block quoted text is a direct quote from Tom Christiansen's post.

      Given that the original poster asked about using "tee.exe", I assume he's running a Windows variant. Neither csh nor the bourne shell nor even dd is installed on Windows by default; and so it's not a great idea to assume that his default shell isn't just "command.com" in his case.

      Your points are all correct; just probably a bit too UNIX centric for the original poster to make use of. It's nice to want to help, but let's try to pick up on the subtle cues (operating system in use, etc.) that will make our advice that much more useful to the people who ask for it.

      The wiser we all try to be, the more powerful the monestary will become, until one day we TAKE OVER THE WORLD!!! :-)

        You are correct. I am running a windows XP/2000 machine and most of the solutions are Unix centric and I am not able to use them.
      Great post. I have one question you may wish to ponder - what the heck is going on with fd 3 in this example? As far as I can see, the manipulations of fd 3 are (as with dd's output in the example) just noise. I know its OT, but I wonder about this.
Re: Redirecting STDOUT and standard error to file
by jhourcle (Prior) on Sep 09, 2005 at 12:11 UTC

    It may be worthwhile to look into the script command:

    script file.log perl -w sample1.pl 2>&1 echo $? exit col -b file.log > stdout.txt

    Note -- script will save _everything_ that goes be the terminal into a file, which is why you need to pass it through col to get a more sane log file. It may be an advantage or disadvantage that everything gets saved, including subsequent commands, until you exit script.

Re: Redirecting STDOUT and standard error to file
by /dev/luser (Acolyte) on Sep 09, 2005 at 10:19 UTC
    The Perl Cookbook has a nice recipe to copy filehandles. For example:
    open (COPYOUT, ">&STDOUT"); open (COPYERR, ">&STERR");
    This book is *highly* recommended :-)
    HTH