On Mon, May 20, 2002 at 08:54:19PM -0700, [EMAIL PROTECTED] wrote:
> Hi,
> 
> I try to write a script that redirects its output, both out and error, to
> a log-file, if it's possible to the screen as well.
> 
> At the moment I'm doing this with 
> 
> open (FILE, ">whatever.txt");
> 
> open (STDOUT, ">&FILE");
> open (SDTERR, ">&FILE");
> 
> 
> But now of course I don't have the output on the screen any more.
> Is it possible to get both?

Yepp.

Leaving the beginner's realm and entering the world of black magic...

    perldoc perltie

Search for 'TIEHANDLE' in there...

And some code to chew on...

    ---------- th.pl ----------
    #!/usr/bin/perl

    use strict;
    use warnings;

    package th;

    use Exporter;
    use FileHandle;
    our @ISA = qw{Exporter FileHandle};

    sub TIEHANDLE {
        my ($ctx, $fname, $old_fh) = @_;
        my $class = ref($ctx) || $ctx;

        my $fh = new FileHandle(">$fname")
            or die "Cannot open logfile '$fname': $!\n";
        my $dup = new FileHandle(">&$$old_fh")
            or die "Cannot dup old filehandle: $!\n";
        my $self = {
            files => [ $fh, $dup ]
        };

        if (fileno($$old_fh) == 2) {
            $self->{old_die} = $SIG{__DIE__};
            $self->{old_warn} = $SIG{__WARN__};
            $SIG{__DIE__} = sub { $self->die_handler(@_) };
            $SIG{__WARN__} = sub { $self->warn_handler(@_) };
        }

        bless $self, $class;
    }

    sub warn_handler {
        my $self = shift;
        print $_ @_ foreach @{$self->{files}};
    }

    sub die_handler {
        my $self = shift;
        print $_ @_ foreach @{$self->{files}};
    }

    sub PRINT {
        my $self = shift;
        print $_ @_ foreach @{$self->{files}};
    }

    sub CLOSE {
        my $self = shift;
        $_->close() foreach @{$self->{files}};
    }

    sub UNTIE {
        my ($self, $count) = @_;
        warn "untieing $count inner refs" if $count > 1;
        $SIG{__WARN__} = $self->{old_warn} if defined $self->{old_warn};
        $SIG{__DIE__}  = $self->{old_die}  if defined $self->{old_die};
    }

    1;

    package main;

    tie *STDERR, "th", "/tmp/my_log.txt", \*STDERR;
    print STDERR "plain print\n";
    warn "You are warned!\n";
    untie *STDERR;
    print STDERR "Untied\n";
    ---------- th.pl ----------

Notes:

tie *STDERR, "th", "/tmp/my_log.txt", \*STDERR;

    Since the constructor TIEHANDLE isn't passed the tied filehandle we
    need to pass it explicitely as the last parameter.

sub TIEHANDLE:

    my $dup = new FileHandle(">&$$old_fh")

        Since we catch writes to the original filehandle we need to
        duplicate it to avoid recursion

            print STDERR "Failure"
              calls th::PRINT
                which prints to STDERR and thus 
                  calls th::PRINT
                    ...

    if (fileno($$old_fh) == 2) {...

        If we print to STDERR we need to catch $SIG{__WARN__} and
        $SIG{__DIE__}.  We store the original handlers to daisy-chain to
        them after we did our printing.
        
sub UNTIE:

    warn "untieing $count inner refs" if $count > 1;

        Since our object still lives when we're in here, the ref-count
        is still 1.  We can ignore that.
        But if we're >1, there's still some variable that's referencing
        us (my $t = tie ...).  See 'perldoc perltie' for a discussion of
        that.

    Finally, we reestablish the old signal handlers.  Since this is
    sample code we don't do any checking if it's sane to restore these.
    (They might have been overridden by other parts of your
    application...)


And the results:
    ---------- snip ----------
    nijushiho:~$ perl th.pl 
    plain print
    You are warned!
    Untied
    nijushiho:~$ cat /tmp/my_log.txt 
    plain print
    You are warned!
    nijushiho:~$ 
    ---------- snip ----------

If you take a look at the perldoc, you'll notice that I only implemented
a subset of the possible functions.  Just add the others as you need
them in your program...

-- 
                       If we fail, we will lose the war.

Michael Lamertz                        |      +49 221 445420 / +49 171 6900 310
Nordstr. 49                            |                       [EMAIL PROTECTED]
50733 Cologne                          |                 http://www.lamertz.net
Germany                                |               http://www.perl-ronin.de 

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to