How do you know if the process of opening the pipe is completed?

Assuming a handle created with the following code:

use IO::File;

my $fh = IO::File->new;

my $pid = $fh->open('some_long_running_proc |') or die $!;

$fh->autoflush(1);
$fh->blocking(0);

and then read with a loop like this:

while (some_condition_here) {
    my @lines = $fh->getlines;
    ...
    sleep 1;
}

What do I put as some_condition_here, which will return false if the process at the other end of the channel is completed?

Testing for $fh->eofwill not work, as the process can still work without printing any new lines. Testing for $fh->openedseems nothing helps.

I am currently using $pid =! waitpid($pid, WNOHANG)one that seems to work in a POSIX compatible environment. Is this the best way? What's on Windows?

+5
source share
4 answers

When using select,

use strict;
use warnings;

use IO::Select qw( );

sub process_msg {
    my ($client, $msg) = @_;
    chomp $msg;
    print "$client->{id} said '$msg'\n";
    return 1;  # Return false to close the handle.
}

my $select = IO::Select->new();
my %clients;

for (...) {
    my $fh = ...;
    $clients{fileno($fh)} = {
        id  => '...'
        buf => '',
        # ...
    };

    $select->add($fh);
}

while (my @ready = $select->can_read) {
    for my $fh (@ready) {
        my $client = $clients{ fileno($fh) };
        our $buf; local *buf = \( $client->{buf} );

        my $rv = sysread($fh, $buf, 64*1024, length($buf));
        if (!$rv) {
            if (defined($rv)) {
                print "[$client->{id} ended]\n";
            } else {
                print "[Error reading from $client->{id}: $!]\n";
            }

            print "[Incomplete message received from $client->{id}]\n"
                if length($buf);

            delete $clients{ fileno($fh) };
            $select->remove($fh);
            next;
        }

        while ($buf =~ s/^(.*\n)//) {
            if (!process_msg($client, "$1")) {
                print "[Dropping $client->{id}]\n";
                delete $clients{ fileno($fh) };
                $select->remove($fh);
                last;
            }
        }
    }
}
+5

EOF?

while (<$fh>) {
    ...
    sleep 1;
}

, . , , .

, , some_long_running_proc? , select, , .

+2

.

select , .

+2

select(), , - , .

Personally, I prefer to use IO :: Multiplex, especially if you are multiplexing input from several different descriptors, but this might not apply in this case.

+1
source

All Articles