in reply to Filtering my own stderr

This seems like such a dumb idea, but maybe it'll work...
$|=1; attach_stderr_filter(); while (<>) { print "To STDOUT: $_"; print STDERR "To STDERR: $_"; } sub attach_stderr_filter { my($pid); # This is the top secret part :) $pid = open(STDERR, '|-'); defined $pid or die "Cannot fork: $!\n"; if($pid) { return; } # child, now prints to STDERR. while (<STDIN>) { s/foo/bar/; print STDERR "$_"; } }
Woot, what do you know, it DOES work. Cool!
--
Mike

Replies are listed 'Best First'.
Re: Re: Filtering my own stderr
by Anonymous Monk on Nov 02, 2002 at 13:38 UTC
    Mike

    Many thanks for your reply and sorry for taking a while to respond...

    <confusion>
    Er, yes, that does work. Ok, then. Given that open(STDERR, '|-'); was actually the first thing I tried and it did not work for me, I obviously did something stupid. It turns out that I did two stupid things. The first was that I did not try all the alternatives against a simple test case. The second was that I did not read the source of P::RD carefully enough.

    ...Time passes while Kevin reads P::RD properly this time...

    The output I am concerned about is actually written to a format, not directly to STDERR. Why does this matter? Because the format is opened by dup(2)ing STDERR, which gives a fresh file descriptor. So, I can sit there in the child waiting for output on STDERR until I am blue in the face and it will not get me anywhere.
    </confusion>

    So, what now? It does not seem as though I can open an output filter, since I do not know to which file descriptor I should listen. Perhaps I could spin around all of them, but that sounds pretty obscure.

    How about tie'ing the format to a suitable class? Well, this partially works. As it happens, P::RD both prints and writes to the format. The prints come through fine but the writes do not. It seems as though writes to a format cannot be tied. See the example code below:

    use strict; use warnings; package Log::OPG::Info; use Tie::Handle; use base qw(Tie::StdHandle); sub WRITE { print "Good\n"; } package main; format STDERR = Bad . tie *STDERR, 'Log::OPG::Info'; print STDERR ''; write STDERR;

    Whereas I hope for the output

    Good Good
    I actually get
    Good Bad

    So, either I am missing something obvious, or the follow-up question is:

    "How does one tie writes to a format?"

    Cheers
    Kevin
    

    P.S. I faintly remember that it is possible to name individual slots in hash table entries, along the lines of $::slot{SCALAR} and $::slot{FORMAT}. Perhaps that might form the basis for a solution, but the details escape me.

      Rather than capturing your own STDERR, why not try wrapping your program with a short one that uses IPC::Open3 to launch the original program with STDERR captured.

      You can also do this kind of redirecting in the command-line invocation with any decent shell.