Re: codeopen(INPUT, "INPUT") gives INPUT opened only for output
by mce (Curate) on Nov 16, 2001 at 15:25 UTC
|
Hi,
Why do you close STDOUT. You can use select instead.
I don't see why you use seek in your code
when you open one filehandle for input and one for
output. If you whould have used +> instead,
you would need the seek. (see perldoc perlopentut).
use POSIX;
use strict;
my $TRAP=POSIX::tmpnam();
print "TMPFILE is $TRAP\n";
open(TMPFILE, "+> $TRAP") or die $!;
select TMPFILE;
eval { print 'Waka Waka' };
seek(TMPFILE,0,0);
my $input=<INFILE>;
close(INFILE>;
select STDOUT;
print $input;
This works fine for me.
---------------------------
Dr. Mark Ceulemans
Senior Consultant
IT Masters, Belgium
| [reply] [d/l] |
|
|
- mce As tilly says select only handles prints without
a specified handle but not explicit STDOUT.
- mce I *did* originally have an open with >+
which s why that seek is still there.
--
perl -p -e "s/(?:\w);(<A HREF="/index.pl?node=st&lastnode_id=2437">st<
+/A>)/'\$1/mg"
| [reply] [d/l] |
Re: codeopen INPUT opened only for output
by Anarion (Hermit) on Nov 16, 2001 at 16:28 UTC
|
Your trying to open a non defined filehandle, if you want to retore the output, you have to save it before closing it.
Try printing fileno(STDOUT).
#!/usr/bin/perl -lw
use POSIX;
my $TRAP = POSIX::tmpnam();
print STDERR "STDOUT= ".fileno(STDOUT);
close(STDOUT);
print STDERR "STDOUT= ".fileno(STDOUT);
open(STDOUT, ">$TRAP") || die("$!: $TRAP"); #+> didn't work
eval "print 'Waka waka!'";
seek(STDOUT, 0, 0);
print STDERR "STDOUT= ".fileno(STDOUT);
close(STDOUT);
open(STDOUT, ">-");
print STDERR "STDOUT= ".fileno(STDOUT);
open(INPUT, "<$TRAP") || die("$!: $TRAP");
$chldoutput = <INPUT>;
Theres no errors or warnings, perhaps you want to save STDOUT before closing it
open(MYSTDOUT, ">&STDOUT");
and later restore it with
open(STDOUT, ">&MYSTDOUT");
$anarion=\$anarion;
s==q^QBY_^=,$_^=$[x7,print
| [reply] [d/l] [select] |
Re (tilly) 1: codeopen(INPUT, "<INPUT") gives INPUT opened only for output
by tilly (Archbishop) on Nov 16, 2001 at 20:59 UTC
|
use File::Temp qw(tempfile);
my $temp_fh = tempfile();
my $saved_fh = select($temp_fh);
eval "print 'Waka waka!'";
seek ($temp_fh, 0, 0);
select($saved_fh);
$text = join '', <$temp_fh>;
print "The text was '$text'\n";
In fact looking at this, you can add error trapping etc while turning this into a function:
use File::Temp;
use Carp;
# Takes code to be evaled, supresses printing and returns
# the text that would have been printed.
sub eval_print_trap {
my $code = shift;
my $temp_fh = tempfile();
my $saved_fh = select($temp_fh);
eval($code);
select($saved_fh);
if ($@) {
confess("Evaling \n'$code'\ngave error $@");
}
seek($temp_fh, 0, 0);
wantarray ? <$temp_fh>: join '', $temp_fh;
}
The point being, of course, that the error handling is a Good Thing to add, you now have a piece of reusable functionality which does not assume that STDOUT had been the previous selected default filehandle, and in your code wouldn't you rather see:
my $output = eval_print_trap("print 'Waka waka!'");
than all of the garbage it required?
Caveat programmer: Perl's select will only redirect prints to the default output from Perl code. You will not trap error output, and you will not trap any printing that comes within C code or other programs. Good luck if you plan to call system. | [reply] [d/l] [select] |
|
|
#!/usr/bin/perl -w
use strict;
use IO::Scalar;
use Carp;
my $out = eval_print_trap(<<'EOC');
print "Hello World\n";
print STDOUT "Hello again\n";
print STDERR "stderr is here too\n";
print "this uninit warning is captured:$a\n";
warn "and explicit warnings as well";
system(q|echo "Can't have everything!"|);
EOC
print "***\n$out***\n";
print "done\n";
sub eval_print_trap {
my $code = shift;
my $string;
my $SH = IO::Scalar->new_tie(\$string);
{
local *STDOUT = $SH;
local *STDERR = $SH;
local $SIG{__WARN__} = sub{print @_};
eval($code);
}
if($@){
confess "Evaling\n'$code'\ngave error $@";
}
return $string;
}
__END__
### could also have this at the end:
seek($SH,0,0);
wantarray ? <$SH> : $string;
| [reply] [d/l] |
|
|
Yeah I should have mentioned I didn't want to use IO::Scalar;
at least File::Temp is standard in 5.6.1 and there is a fall
back which is always available.
--
perl -p -e "s/(?:\w);(<A HREF="/index.pl?node=st&lastnode_id=2437">st<
+/A>)/'\$1/mg"
| [reply] [d/l] |
|
|
tilly I am using File::Temp, that's
where tmpnam comes from (with a fallback to POSIX).
I should point out that the code in the eval
will be unknown, not wirtten by me no idea what's in it.
Also, I have already dupped STDERR to STDOUT.
I would prefer to use tmpfile; even if I can't fallback then;
but since I'm trying to *replace* STDOUT
(for those who explicitly print to it, which
as you pointed out select will do nothing about).
But I as unable to dup the filehandle to STDOUT.
I tried doing a
my $TRAP = tmpfile();
$no = fileno($TRAP);
on it and opening as
open(STDOUT, ">&$fileno");
as well as open(STDOUT, ">&=$fileno");
Neither of which worked so I figured I had to roll my own.
--
perl -p -e "s/(?:\w);(<A HREF="/index.pl?node=st&lastnode_id=2437">st<
+/A>)/'\$1/mg"
| [reply] [d/l] [select] |
Re: open(INPUT, "<INPUT") gives INPUT opened only for output
by belg4mit (Prior) on Nov 16, 2001 at 22:27 UTC
|
I should point out that the code in the eval will be unknown, not wirtten by me no idea what's in it.
Also, I have already dupped STDERR to STDOUT as well.
UPDATE: Clearly dupping STDERR it is not right,
fixed that I am now trying to open STDERR to
the same file as STDOUT in the same way
(though one is > and the other is >>)
UPDATE 2:
I should also note that I'd rather not use IO::Scalar
as it's not standard even in 5.6.1. Maybe I'm just
asking for too much? But it seems that the only
thing preventing a reasonable solution is the warning about
using the filehandles once. And I'd like to understand it
before I do local $^W=0;
--
perl -p -e "s/(?:\w);(<A HREF="/index.pl?node=st&lastnode_id=3333">st<
+/A>)/'\$1/mg"
| [reply] [d/l] [select] |
Re: Re: (Anarion) open(INPUT, "<INPUT") gives INPUT opened only for output
by belg4mit (Prior) on Nov 16, 2001 at 22:39 UTC
|
This is actually a followup to: Re: codeopen INPUT opened only for output
a) yes I was able to get it to work with
a double dup to save STDOUT (see b below)
however I don't understand why I cannot
recover STDOUT by one of:
open(STDOUT, '>-');
open(STDOUT, '>&=1');
b)The folloing is similar to what you posted
with some updates *but* if you run it with
-w -Mstrict you get: Name "main::SAVE" used only once: possible typo
use POSIX;
local $/ = undef;
my $chldoutput;
my $TRAP = POSIX::tmpnam();
print "Gonna use $TRAP\n";
open(SAVE1, ">&STDOUT");
open(SAVE2, ">&STDERR");
close(STDOUT);
open(STDERR, ">$TRAP");
open(STDOUT, ">>$TRAP") || die("$!: $TRAP"); #+> didn't work
eval "print STDERR 'Scary... ';print 'Waka waka!'";
close(STDOUT);
close(STDERR);
open(STDOUT, ">&SAVE1");
open(STDERR, ">&SAVE2");
open(INPUT, $TRAP) || die("$!: $TRAP");
$chldoutput = <INPUT>;
print "ABC: $chldoutput\n";
unlink($TRAP);
--
perl -p -e "s/(?:\w);(<A HREF="/index.pl?node=st&lastnode_id=3333">st<
+/A>)/'\$1/mg"
| [reply] [d/l] [select] |
Re: codeopen(INPUT, "INPUT") gives INPUT opened only for output
by belg4mit (Prior) on Nov 16, 2001 at 13:18 UTC
|
s/Yields Filehandle OUTPUT/Yields Filehandle INPUT/
I s/OUPUT/INPUT/ while editing as I thought "OUTPUT opened only for output"
sounded odd and I missed one.
--
perl -p -e "s/(?:\w);(<A HREF="/index.pl?node=st&lastnode_id=3333">st<
+/A>)/'\$1/mg"
| [reply] [d/l] |