Search code examples
perlpipexargs

When opening n pipes to child processes executing xargs from Perl, n-1 processes receive an empty line


...on the other side if I write something to the pipes before opening the next one, this doesn't happen.

The following code should make it clearer:

sub test_concurrent_pipes
{
    my $write_at_once = $_[0];
    my $pipe_handle;
    my @pipe_handle_list;
    my $i;
    foreach $i ( 1..3 )
    {
        open ( $pipe_handle, "| xargs echo" ) or die ( "Cannot open pipe.\n" );
        if ( $write_at_once == 1 )
        {
          print $pipe_handle "Hello\n";
        }
        push( @pipe_handle_list, $pipe_handle );
    }
    foreach $pipe_handle ( @pipe_handle_list )
    {
        print $pipe_handle "world\n";
    }
    foreach $pipe_handle ( @pipe_handle_list )
    {
        close ( $pipe_handle );
    }
}

print "Test 0: open all pipes before writing\n";
test_concurrent_pipes(0);

print "Test 1: write Hello before opening next pipe\n";
test_concurrent_pipes(1);

Running the test I get

./test_pipe_2_xargs.pl 
Test 0: open all pipes before writing


world world world
Test 1: write Hello before opening next pipe
Hello
Hello
Hello world world world

As you can see in Test 0, opening the 3 pipes in a row without any output in between generates 2 empty lines. Strangely enough, if I substitute xargs echo with cat - there are not empty lines produced. The xargs behavior seems also to contradict its man page, which states Blank lines on the standard input are ignored.

How can I avoid those empty lines?

This happens with Perl 5.14.2 on cygwin/XP and with Perl 5.8.8 on HP-UX 11.00.

I write what I'm really trying to do at the end, since it's irrelevant here:

efficiently cleanup all derived objects visible from all Clearcase views through a Perl script which forks one process per view to remove the files (xargs rm) before removing them from the VOBs (rmdo).


Solution

  • Making "creation loop" use local variable ( my $pipe_handle ) fixes the problem.

    foreach $i ( 1..3 )
    {
        open ( my $pipe_handle, "| xargs echo" ) or die ( "Cannot open pipe.\n" );
        ...
    }