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]