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

I'm using a CGI script that prints a lot of data to STDOUT for a web browser, and at the same time prints it to a local file. The code looks like this:
open(STDOUT, "| tee $filename"); # print normally, with output going to the browser and to the file $fi +lename close(STDOUT);
FYI, tee is a program that simply replicates standard output.

My problem is, I want to print only part out the output to a file - that is, print stuff to the browser, print more stuff to both the browser and the file, then just print to the browser again. So, what I want is to pipe things to tee, then turn it off - "unpipe" it.

Suggestions for doing this a completely different way are also very welcome, but I am not sure what modules are installed on this system so it might be better to avoid using any.

Replies are listed 'Best First'.
RE: Multiple outputs in a CGI script
by tilly (Archbishop) on Aug 09, 2000 at 23:06 UTC
    Go steal some code from Tom Christiansen.

    Use that Tie::Tee to create a handle called "TEE", and then switch between TEE and STDOUT using select. See "perldoc -f select" for details.

Re: Multiple outputs in a CGI script
by maverick (Curate) on Aug 09, 2000 at 23:10 UTC
    Something like this may do what you need. Instead of 'switching' tee on and off, use two filehandles.
    # unbuffer STDOUT $| = 1; open(TEE, "| tee $filename") || die "Can't open pipe: $!"; # unbuffer output to the pipe. select(TEE); $| = 1; select(STDOUT); print TEE "some stuff that goes both places\n"; print "some stuff that goes to the browser\n"; print TEE "some more stuff that goes places\n";
    I've not tested this, but it should do the trick. If you get output in the wrong sequence, the some of the output is being buffered somewhere along the line. Setting $| should keep that from happening...

    /\/\averick

      I was going to suggest something like that, but then I realized that I did not know off of the top of my head what would happen with buffering, whether tee did it, or not. In general if I don't know the answer to a question like that immediately, I usually think up a pure Perl solution. Besides which, then I know it is cross-platform code. :-)
        I try to stay cross platform too, but since his question used tee, I figure there's not much harm in having my solution use it :)

        The Tie::Tee example on the link you posted is really slick, and is probably the best solution. You wouldn't have the buffering question since there's only one place where you'd write to STDOUT, it wouldn't be exec-ing an external program, and it would be cross-platform.

        /\/\averick

Re: Multiple outputs in a CGI script
by chromatic (Archbishop) on Aug 09, 2000 at 23:08 UTC
    One short answer, wrap these two kinds of output in subroutines. Long answer:
    sub output { my $text = shift; print STDOUT $text; } sub output_logged { my $text = shift; local *STDOUT; open(STDOUT, "| tee $filename") || die "Can't open pipe: $!"; print STDOUT $text; close STDOUT; }
    Other options include returning a filehandle from a subroutine and printing to that wherever you go. Remember, you can return a typeglob and capture it in a scalar.
Re: Multiple outputs in a CGI script
by Cirollo (Friar) on Aug 09, 2000 at 23:34 UTC
    Thanks for all the answers. It seems that a solution similar to Maverick's is my best bet -
    # print stuff just to the browser open(TEE, "| tee $filename") || die "Can't open pipe: $!"; select(TEE); $| = 1; # print stuff to both file and browser select(STDOUT); # print stuff to just the browser