Click here to get back home

IPC::Open3 : Why can't I catch program output here?

 HomeNewsGroups | Search | About
 comp.lang.perl.misc    Post an article   get this group's latest topics as an RSS feed add this group's latest topics to your My MSN content add this group's latest topics to your My Yahoo content
Subject Author Date
IPC::Open3 : Why can't I catch program output here? Ronny 05-05-2008
Posted by Ronny on May 5, 2008, 9:12 am
Please log in for more thread options
I try to use the program below to catch standard output and standard
error
of a process. The program itself runs well, and it *does* write at
least to
standard output, but in the code below, the line saying "### READING"
is never printed and @msg is still empty afterwards. This means that
$selector->can_read() must have returned false already the first time
it was called. Any suggestion on what could I have done wrong here?

my @msg;
my $pid=open3(*CMD_IN,*CMD_OUT,*CMD_ERR,@cmd)
or confess "Open3 error: $!\n";;
$SIG = sub {
waitpid($pid,0)>0 &&
print "SIGCHILD status=$? pid=$pid\n";
};
my $selector=IO::Select->new();
$selector->add(*CMD_ERR,*CMD_OUT);
while(my @ready=$selector->can_read()) {
foreach my $fh (@ready) {
print "### READING\n";
push @msg,scalar(<$fh>);
$selector->remove($fh) if eof($fh);
}
}
close CMD_OUT;
close CMD_ERR;

Posted by Ben Morrow on May 5, 2008, 6:55 pm
Please log in for more thread options

> I try to use the program below to catch standard output and standard
> error of a process. The program itself runs well, and it *does* write
> at least to standard output, but in the code below, the line saying
> "### READING" is never printed and @msg is still empty afterwards.
> This means that $selector->can_read() must have returned false already
> the first time it was called. Any suggestion on what could I have done
> wrong here?

Works for me here (i686-freebsd). What platform are you on, and what
command are you trying to run? In general, if you can provide a complete
program people can copy/paste/run, you're more likely to get help: in
this case, you omitted the 'use' lines and the contents of @cmd.

> my @msg;
> my $pid=open3(*CMD_IN,*CMD_OUT,*CMD_ERR,@cmd)
> or confess "Open3 error: $!\n";;

I would normally say 'Use lexical filehandles!' at this point;
unfortunately, IPC::Open3 was written before they existed and the
obvious way

my $pid = open3(my $CMD_IN, my $CMD_OUT, my $CMD_ERR, @cmd)...

doesn't work (and can't be made to since undef is already meaningful).
So you have to fall back to the old method of using Symbol::gensym:

use Symbol qw/gensym/;

my ($CMD_IN, $CMD_OUT, $CMD_ERR) = (gensym, gensym, gensym);
my $pid = open3($CMD_IN, $CMD_OUT, $CMD_ERR, @cmd)...

which is definitely ugly, but IMHO worth it (if you must use IPC::Open3
at all: I'd use IPC::Run instead). For one thing, these gensymmed
filehandles close when they go out of scope, just like more usual
lexical filehandles. Of course, I'd use a hash to hold the filehandles:

my %CMD = map {($_, gensym)} qw/IN OUT ERR/;
my $pid = open3(@CMD{qw/IN OUT ERR/}, @cmd)...

> $SIG = sub {
> waitpid($pid,0)>0 &&
> print "SIGCHILD status=$? pid=$pid\n";
> };
> my $selector=IO::Select->new();
> $selector->add(*CMD_ERR,*CMD_OUT);
> while(my @ready=$selector->can_read()) {
> foreach my $fh (@ready) {
> print "### READING\n";
> push @msg,scalar(<$fh>);
> $selector->remove($fh) if eof($fh);

Using eof is nearly always a mistake: it's almost always better to check
the return value of your read statement instead. Something like

my $msg = <$fh>;
defined $msg
? push @msg, $msg
: $selector->remove($fh);

This also means you don't get a spurious undef on the end of @msg.

Ben

--
I must not fear. Fear is the mind-killer. I will face my fear and
I will let it pass through me. When the fear is gone there will be
nothing. Only I will remain.
ben@morrow.me.uk Frank Herbert, 'Dune'

Posted by Ilya Zakharevich on May 5, 2008, 8:26 pm
Please log in for more thread options
[A complimentary Cc of this posting was NOT [per weedlist] sent to
Ben Morrow
> I would normally say 'Use lexical filehandles!' at this point;
> unfortunately, IPC::Open3 was written before they existed and the
> obvious way
>
> my $pid = open3(my $CMD_IN, my $CMD_OUT, my $CMD_ERR, @cmd)...
>
> doesn't work (and can't be made to since undef is already meaningful).

I have no idea what you mean here.

sub open3 ($$$$@) {
$_[0] = IO::Handle->new unless defined $_[0]; # Or whatever is THE
initializer
...
}

Yours,
Ilya

Posted by Ben Morrow on May 6, 2008, 12:00 pm
Please log in for more thread options

> [A complimentary Cc of this posting was NOT [per weedlist] sent to
> Ben Morrow
> > I would normally say 'Use lexical filehandles!' at this point;
> > unfortunately, IPC::Open3 was written before they existed and the
> > obvious way
> >
> > my $pid = open3(my $CMD_IN, my $CMD_OUT, my $CMD_ERR, @cmd)...
> >
> > doesn't work (and can't be made to since undef is already meaningful).
>
> I have no idea what you mean here.
>
> sub open3 ($$$$@) {
> $_[0] = IO::Handle->new unless defined $_[0]; # Or whatever is THE
> initializer
> ...
> }

Yeah, in general you can do that; however, for the specific case of
open3, the docs say

If CHLD_ERR is false, or the same file descriptor as CHLD_OUT, then
STDOUT and STDERR of the child are on the same filehandle.

so at least the CHLD_ERR filehandle can't be autovivified. Presumably it
is felt that this behaviour can't be changed.

Ben

--
"If a book is worth reading when you are six, * ben@morrow.me.uk
it is worth reading when you are sixty." [C.S.Lewis]

Posted by Ilya Zakharevich on May 6, 2008, 8:04 pm
Please log in for more thread options
[A complimentary Cc of this posting was NOT [per weedlist] sent to
Ben Morrow
> > sub open3 ($$$$@) {
> > $_[0] = IO::Handle->new unless defined $_[0]; # Or whatever is THE
> > initializer
> > ...
> > }

> Yeah, in general you can do that; however, for the specific case of
> open3, the docs say
>
> If CHLD_ERR is false, or the same file descriptor as CHLD_OUT, then
> STDOUT and STDERR of the child are on the same filehandle.

Thanks, I forgot about this semantic. Which does not mean that one
could not write ALSO open3_autovivify... ;-)

Yours,
Ilya

Similar ThreadsPosted
IPC::Open3 August 24, 2005, 2:23 pm
IPC::Open3 November 11, 2006, 8:10 pm
How do you use IPC::Open3.... January 19, 2008, 5:11 pm
open3 and signals September 20, 2004, 8:43 pm
IPC::Open3 issue August 24, 2005, 3:21 pm
can't get STDERR using open3... December 20, 2006, 3:21 pm
IPC::open3: What goes wrong? August 1, 2007, 1:05 pm
Example for open3 on windows? May 20, 2008, 1:33 am
Open3 with nonblocking reads September 3, 2004, 7:51 am
IPC::Open3 and the error filehandle October 26, 2007, 9:33 am

Our other projects:

Art Dolls, Fairies and Mermaids - Sunnyfaces.net

Roy's Linux, Programming and Search Engines messages

1-Script XML SitemapXML Sitemap