|
Prev: FAQ 4.9 How can I output Roman numerals?
Next: interacting with another program that requires input
From: Ronny on 5 May 2008 09:12 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{CHLD} = 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;
From: Ben Morrow on 5 May 2008 18:55 Quoth Ronny <ro.naldfi.scher(a)gmail.com>: > 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{CHLD} = 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(a)morrow.me.uk Frank Herbert, 'Dune'
From: Ilya Zakharevich on 5 May 2008 20:26 [A complimentary Cc of this posting was NOT [per weedlist] sent to Ben Morrow <ben(a)morrow.me.uk>], who wrote in article <vrf4f5-d901.ln1(a)osiris.mauzo.dyndns.org>: > 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
From: Darren Dunham on 6 May 2008 17:37 xhoster(a)gmail.com wrote: > ddunham(a)taos.com (Darren Dunham) wrote: >> Ben Morrow <ben(a)morrow.me.uk> wrote: >> > 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). >> >> What's wrong with the above? > > It causes cmd's stderr to go to $CMD_OUT rather than the obviously > intended $CMD_ERR. I don't know that it's obviously intended. It took me quite a while to realize that I even had an option to return output and error on a single filehandle. I mention that explicitly because the OP might have been having issues with selecting between the two, when reading them combined may have been preferable. However, if you do want them separated, then the other choices offered seem quite verbose. Instead of them, I would pass in a (defined) filehandle. That takes one more line of code (two if you count bringing in the FileHandle module. my $CMD_ERR = FileHandle->new(); my $pid = open3(my $CMD_IN, my $CMD_OUT, $CMD_ERR, @cmd)... -- Darren Dunham ddunham(a)taos.com Senior Technical Consultant TAOS http://www.taos.com/ Got some Dr Pepper? San Francisco, CA bay area < This line left intentionally blank to confuse you. >
From: Darren Dunham on 6 May 2008 12:01 Ben Morrow <ben(a)morrow.me.uk> wrote: > 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). What's wrong with the above? The only issue I see is that Open3 will not autogenerate a filehandle for stderr (instead it will combine stdout and stderr and place them both on the $CMD_OUT filehandle). I actually use that method so I don't have to select between two filehandles and can just read one at a time. # capture STDOUT and STDERR, on a single filehandle use IPC::Open3; open3(my $cmd_in, my $cmd_out, undef, @cmd); while (<$cmd_out>) { ... } -- Darren Dunham ddunham(a)taos.com Senior Technical Consultant TAOS http://www.taos.com/ Got some Dr Pepper? San Francisco, CA bay area < This line left intentionally blank to confuse you. >
|
Next
|
Last
Pages: 1 2 Prev: FAQ 4.9 How can I output Roman numerals? Next: interacting with another program that requires input |