Discussion:
Can Perl redirect STDOUT to file AND to command window?
(too old to reply)
r***@gmail.com
19 years ago
Permalink
I have done standard Perl STDOUT redirection to a pipe and to a file,
however, I have been searching for a way to redirect STDOUT to a file
and to the command window at the same time. So far, no luck - is this
possible?

Ryan
u***@DavidFilmer.com
19 years ago
Permalink
I have been searching for a way to redirect STDOUT to a file and to
the command window at the same time. So far, no luck - is this possible?
Sure. use IO::Tee (http://search.cpan.org/~kenshan/IO-Tee-0.64/Tee.pm)

Or, if you want to get REALLY cool, use Log::Dispatch and attach
handlers for file and screen (and you can fire the handlers based on
the log level of the message, so you can fire one or both handlers
based on the level you stipulate). I use Log::Dispatch for ALL of my
process messages (I rarely use "print" statements except for trivial
code).
u***@DavidFilmer.com
19 years ago
Permalink
Post by u***@DavidFilmer.com
Or, if you want to get REALLY cool, use Log::Dispatch and attach
handlers for file and screen...
Here's an example of how to do this. Log::Dispatch is really a great
way to handle process messages (and you can attach other methods if you
wish - it can send you e-mail, or log to XML files or to databases)...

#!/usr/bin/perl
use strict; use warnings;

use Log::Dispatch::Screen;
use Log::Dispatch::File;

my $log = Log::Dispatch -> new; #This is the logger

#Logging method for terminal output. Fires at 'debug' or higher
$log ->add( Log::Dispatch::Screen ->new(
name => 'screen',
min_level => 'debug',
stderr => 0, )
);
#Logging method for file output. Fires at 'info' or higher
$log ->add( Log::Dispatch::File ->new(
name => 'file',
min_level => 'info',
filename => '/tmp/whatever.log',
mode => 'append' )
);

### Now the logging methods are set up. We can invoke the logger
### by passing it a message at a particular urgency level, namely:
### debug info notice warning error critical alert emergency
### The logger will fire ANY and ALL methods which are defined as
### equal to or less than the urgency level we stipulate.

$log -> debug("This message goes to the screen only\n");
$log -> info("This message goes to BOTH screen and file.\n");

$log -> log_to(name => 'file',
level => 'info',
message => "Force message to go to file ONLY\n");

__END__

# Never use 'print()' again!
u***@DavidFilmer.com
19 years ago
Permalink
Post by u***@DavidFilmer.com
Here's an example of how to do this. Log::Dispatch is really a great
way to handle process messages...
But, wait, there's more! If you use the Log::Dispatch module in the
next 30 minutes, you will get callback capability at NO ADDITIONAL
COST! That's right - a billion dollar value is yours FREE!

Are you tired of having to fuss with linefeeds on your output messages?
Define a callback! Do you want to timestamp each line that you write
to your logfile (but not bother to show the timestamp on STDOUT
messages? Define a callback! For example:

my $add_lf = sub { my %p = @_; "$p{'message'}\n"};
my $add_timestamp = sub { my %p = @_;
sprintf "%s - %s", scalar(localtime),
$p{'message'}; };

OK, now you've defined two callbacks (one to add linefeeds, one to add
timestamps). Assuming that you want to add linefeeds to every single
thing that you output, you would define your logger to always use the
$add_lf callback:

$log = Log::Dispatch->new ( callbacks => $add_lf );

But you only want to call the timestamp-er on the 'file' method, so you
would define that method like this:
$log ->add( Log::Dispatch::File ->new(
name => 'file',
min_level => 'info',
filename => '/tmp/whatever.log',
callbacks => $add_timestamp,
mode => 'append' )
);

Now you can log even multiple lines, such as this:

$log->debug('line 1', 'line 2', 'line 3');

And it will automatically add linefeeds to each line, and it will
timestamp each line (but only in the file, not on the terminal).

Call CPAN now - webservers are standing by to take your order!
r***@gmail.com
19 years ago
Permalink
Thanks for the start, IO::Tee works well like this:

use strict;
use IO::Tee;

my $tee = IO::Tee->new(\*STDOUT,">out.txt");
print $tee "test\n";

However, I am looking for something like this where I dont need to
print to the $tee handle:

use strict;
use IO::Tee;

my $tee = IO::Tee->new(\*STDOUT,">out.txt");
open(STDOUT, ">&$tee");
print "test\n";

This creates out.txt and prints "test" to the screen but not to out.txt

Do I need to use tie() ?

tie(*STDOUT, "mypackage");

R
u***@DavidFilmer.com
19 years ago
Permalink
Post by r***@gmail.com
However, I am looking for something like this where I dont need to
Hmmm. I don't know if you can do this. 'print' (by default) goes to
STDOUT. But you want to redefine STDOUT as a tee that goes to a file
and... STDOUT. But STDOUT is now a tee that goes to a file and...
STDOUT. This goes on forever.
r***@gmail.com
19 years ago
Permalink
Yeah...I got stuck in that loop myself, my watchdog kicked....bummer, I
guess the consensus for this thread is "no" unless you want to be
explicit about the handle.

Thanks for the help...

R
Anno Siegel
19 years ago
Permalink
Post by u***@DavidFilmer.com
Post by r***@gmail.com
However, I am looking for something like this where I dont need to
Hmmm. I don't know if you can do this. 'print' (by default) goes to
STDOUT.
It goes to the filehandle chosen by select(). The default is STDOUT.
Post by u***@DavidFilmer.com
But you want to redefine STDOUT as a tee that goes to a file
and... STDOUT. But STDOUT is now a tee that goes to a file and...
STDOUT. This goes on forever.
One could tie STDOUT to something that writes to the file and to
what STDOUT used to be before the tie. Using the IO::Tee module:

use IO::Tee;

my $file;
open $file, '>', $_ or die "Can't create '$_': $!" for '/tmp/x';
my $tee = IO::Tee->new( \ *STDOUT, $file);
select $tee;

print "$_\n" for qw( hihi haha hoho);

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.
x***@gmail.com
19 years ago
Permalink
Post by u***@DavidFilmer.com
use strict;
use IO::Tee;
my $tee = IO::Tee->new(\*STDOUT,">out.txt");
print $tee "test\n";
However, I am looking for something like this where I dont need to
How about just selecting $tee so that it becomes the default output handle?

select $tee;
Post by u***@DavidFilmer.com
use strict;
use IO::Tee;
my $tee = IO::Tee->new(\*STDOUT,">out.txt");
open(STDOUT, ">&$tee");
Always check the success of your open.

Xho
--
-------------------- http://NewsReader.Com/ --------------------
Usenet Newsgroup Service $9.95/Month 30GB
r***@gmail.com
19 years ago
Permalink
Post by x***@gmail.com
select $tee;
BRILLIANT!

I dont know how that was missed...thanks for the help.
r***@gmail.com
19 years ago
Permalink
**** SUMMARY **** (for those on the Google quest)

use strict;
use IO::Tee;

my $tee = IO::Tee->new(\*STDOUT,">out.txt");
select $tee;

print "Hello World\n"; # will print Hello World to both cmd window and
./out.txt

R
Sherm Pendley
19 years ago
Permalink
Post by r***@gmail.com
I have done standard Perl STDOUT redirection to a pipe and to a file,
however, I have been searching for a way to redirect STDOUT to a file
and to the command window at the same time. So far, no luck - is this
possible?
If you're on a *nix, "man tee".

sherm--
--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org
r***@gmail.com
19 years ago
Permalink
Unfortunately, I am on windows (else I wouldnt be here ;)

My situation is a bit complex and requires me to do all the redirection
within the script, so I can't get away with this either:

perl my_script.pl | tee out.txt

R
Purl Gurl
19 years ago
Permalink
Post by r***@gmail.com
I have done standard Perl STDOUT redirection to a pipe and to a file,
however, I have been searching for a way to redirect STDOUT to a file
and to the command window at the same time. So far, no luck - is this
possible?
Simply print to both.

print OUTFILE "my data";
print "my data";

Purl Gurl
r***@gmail.com
19 years ago
Permalink
PG,

I don't want to go into too much gory detail, but basically my module
is for concurrent scripting with a simple IPC interface that works via
C++, users of the module don't know that I am redirecting their output
to a file and to the cmd window ;)

R
Purl Gurl
19 years ago
Permalink
Post by r***@gmail.com
PG,
I don't want to go into too much gory detail, but basically my module
is for concurrent scripting with a simple IPC interface that works via
C++, users of the module don't know that I am redirecting their output
to a file and to the cmd window ;)
Writing a C language executable, for Windows, to duplicate filehandles
is very easy. Look around on Google and you will find many already
compiled and ready. I am not about to ask why you want to conceal
this from users, but will advise be sure your executable does not
have any "plaintext" viewable; convert your Plain English words to
hex, ord, or similar. If your executable is opened with a hex editor,
only hex data will be viewed.

Should you need to truly conceal commands, split up your commands
on different lines in your executable so "curious" people cannot convert
your hex entries to ASCII and make sense of what is there.

However, if a person is so curious to snoop around in your executable,
you are already suspect.

What you want to accomplish cannot be done with Perl nor MSDOS,
and be concealed. Even your C executable can be "read" to a degree.

Nonetheless, if your circumstances are users cannot access the
directory where you stash your program, there is no need to conceal.
My presumption this is the case, otherwise users would notice the
file creation, least I would; I track everything a program does to be
sure that program is not messing up my system.

Use of the IO module is fine, except it requires other modules. Pinging
my memory, I believe IO Tie uses two or three supporting modules.
That method will be resource wasteful.

Check on Google. There are lots of compiled binaries available which
will handle your task with ease and efficiency.

Purl Gurl
Loading...