http://qs1969.pair.com?node_id=1176340


in reply to Run and kill external programm after x seconds

You can set an alarm and then time-out after blocking for awhile. Or you could do your reads non-blocking, and iterate until time is up. With a little effort you can also continue doing other work while processing your input. The following example reads from a program that outputs "ping" every few seconds. But when there's no input to read, it does other things (outputs a dot). And when a "ping" is detected, it responds by outputting a "pong".

#!/usr/bin/env perl use strict; use warnings; use Time::HiRes qw(usleep); use IO::Select; use File::Spec::Functions qw(catfile); use constant USLEEP_TIME => 25_000; # Microseconds use constant RUN_TIME => 30; # Seconds my $cmd = catfile((getpwnam($ENV{USER}))[7],'scripts','outputter'); # +This just sets up the path to the external script. You could hard-cod +e it or base it on FindBin if you want. open my $r, '-|', $cmd or die $!; my $s = IO::Select->new($r); __PACKAGE__->run( {read => $r, select => $s, ping => 0}, [ sub { my $self = shift; $self->{select}->can_read(0) } => sub { my $self = shift; my $ifh = $self->{'read'}; chomp(my $i = <$ifh>); print "\n<$i>\n"; $self->{ping} = 1; } ], [ sub { my $self = shift; !$self->{ping}; } => sub { usleep USLEEP_TIME; print "."; STDOUT->flush; } ], [ sub { my $self = shift; $self->{ping}; } => sub { my $self = shift; print "(pong)\n"; $self->{ping} = 0; } ], ); sub run { my ($class, $args) = (shift(), shift()); $args ||= {}; my $s = bless $args, $class; my $time = time(); while(time() < $time + RUN_TIME) { foreach my $step (@_) { $step->[1]->($s) if $step->[0]->($s); } } }

The ping script can look like this:

#!/usr/bin/env perl use strict; use warnings; use IO::Handle; STDOUT->autoflush(1); while (1) { print STDOUT "ping\n"; sleep 2; }

Using a poor-man's event loop (the while loop), and by taking care to not let the "handlers" block, this script is able to accept input and when there's no input spend time doing other things.

When this script exits, the pipe closes and the ping script will receive a signal to terminate.

This is written with Linux in mind. I don't know if it would work for Windows, and don't have a Windows environment to test on anymore.


Dave