tags:

views:

162

answers:

3

The following code is working sort of fine:

open( PIPE, '-|', 'ant' );
for( <PIPE> ) {
    print;
}

However, it doesn't do what I want. Since the Ant build can take 5 minutes, I would like to see the output line by line. Instead, I'm getting the entire input at the end of the process.

Looking at it with the Perl debugger, Perl waits at the 'for' statement, until Ant terminates. Why is that?

+3  A: 

I believe the problem is buffering. You could make the filehandle hot(unbuffered) like so:

select PIPE;
$| = 1; # the pipe is just a coincidence. that's the variable's name
select STDOUT; # select it back

This should disable buffering for PIPE. I read about something like this in Learning Perl, 5TH. See this, also. You should probably also make sure buffering doesn't happen someplace else.

EDIT: the OP posted that replacing the for with while solved the problem

I think I understand now. while gets each line and runs the loop, whereas for acts like foreach and first gets all the lines (it needs list context) and then loops over the lines.

nc3b
Buffering is probably the issue, but the problematic buffer is on Ant's side, not Perl's. You only need to turn off buffering on output pipes, not input pipes. You'll need to find some way to tell Ant not to buffer its output. You can't fix the problem on the Perl side.
cjm
+2  A: 

Found it. The problem is with the 'for' statement.

The following code works as expected

open( PIPE, '-|', 'ant' ); 
while( <PIPE> ) {           # replacing 'for' with 'while'
    print; 
} 

I don't know the reason, but now it is working.

Uri
To understand why, see http://stackoverflow.com/questions/585341/
Joe
If you answered you own question, it's a good idea to edit the original question and add the answer rather than post a reply.
Barry Brown
@Barry Brown posting your own answer and accepting it if no one provides a better answer is accepted (heh) practice on SO. http://meta.stackoverflow.com/questions/12513/stackoverflow-should-i-answer-my-own-question-or-not
hobbs
+4  A: 

Just for completeness (problem was solved as pointed out in the comment to Uri's answer) the problem arose because the for expression evaluates the <> operator in list context (see), equivalently to the following:

foreach $line (@lines = <PIPE>) {
    print $line;
}

In list context, the <> operator tries to read all lines from its input to asign to the list - and the input comes from a process, it will block until the process ends. Only afterwards it it will enter the loop body.

The alternative syntax

while( <PIPE> ) {           
    print; 
} 

is equivalent instead to

while(  $line = <PIPE> ) {
    print $line;
}

i.e., it consumes each line from the input in each loop iteration, and this is what one wants to do in this scenario.

leonbloy