views:

59

answers:

2

I am trying to run bp_genbank2gff3.pl (bioperl package) from another perl script that gets a genbank as its argument.

This does not work (no output files are generated):

   my $command = "bp_genbank2gff3.pl -y -o /tmp $ARGV[0]";

   open( my $command_out, "-|", $command );
   close $command_out;

but this does

   open( my $command_out, "-|", $command );
   sleep 3; # why do I need to sleep?
   close $command_out;

Why?

I thought that close is supposed to block until the command is done:

Closing any piped filehandle causes the parent process to wait for the child to finish... (see http://perldoc.perl.org/functions/open.html).

Edit

I added this as last line:

say "ret=$ret, \$?=$?, \$!=$!";

and in both cases the printout is:

ret=, $?=13, $!=

(which means close failed in both cases, right?)

A: 

I'm not sure what you're trying to do but system is probably better in this case...

sebthebert
I use `open` since I would like to read the command stdout on the fly, which can't be done using `system` as far as I know (`system` waits for the command to finish then return all the output at once). The example above is just a simplified version which does not include this part, but it is immaterial to the problem.
David B
Ok, so you need a "while(<$command_out>) { do stuff }" between your open and close
sebthebert
This is a generic method I'm using. So sometimes I indeed want to to something with what the command sends to stdout, and then I really use the `while` as you suggested. But if I don't why should the command not execute correctly? The command we're discusing here, for example, gets a filename of some format then splits its data into two files of different formats. It generates files and also print some logging messages to stdout. In this case, I don't care about the stdout so I don't use a while. Why should this matter?
David B
+3  A: 
mobrule
I don't get something. My external program indeed tried to write some output (something like "working on..." at the beginning then "done" at the end). But why do you mean by "the perl program closed its end of the pipe"? In other words, why exactly `my @ignore_me = <$command_out>;` do that makes such a difference?
David B
@David B - You get a `SIGPIPE` when one process (your child, in this example) writes to a pipe that the reader (your parent) has already closed. My writing `<$command_out>` in the parent, you are keeping the reading end of the pipe open until the writing end of the pipe finishes.
mobrule
It reads what the child is trying to write. That makes a difference. You are turning the water to the garden hose and plugging the tip of the hose by not reading the output from the program to which you opened a pipe. If you don't want the program's output, use `system`.
Sinan Ünür
@mobrule, @Sinan and @pilcrow - thank you all. This was interesting.
David B