cmd.pl -------------- use Task; my $obj = Task->new("cat","-t"); my $obj = Task->new("sleep 50"); $obj->start(); if($obj->canSendInput) { print $obj->sendInput("Practical Extraction Report Language\n", "Visual C plus plus"); } print "\noutput1:" . $obj->getOutput(); print "\nError:" . $obj->getError(); print "\n"; $obj->stop(); print $obj->sendInput("Second Input"); [thiagu@host1 ~/exe_abs]$ ./cmd.pl Filehandle GEN0 opened only for output at Task.pm line 89. Use of uninitialized value in concatenation (.) or string at Task.pm line 118. 1 Filehandle GEN0 opened only for output at Task.pm line 89. output1: Error: Task.pm ---------------- package Task; use strict; use warnings; use IPC::Open3; use IO::Select; use IO::Handle; use POSIX qw(:sys_wait_h); #Creating Object sub new { my($class, $cmd, @args) = @_; return bless({ cmd => $cmd, args => \@args, pid => undef, stdout => "", stderr => "", }, $class); } #Running the command with arguments supplied and opening file handles for inout, output and error sub start { my $self = shift; my $cmd_to_exe = "$self->{cmd} "."@{$self->{args}}"; # Reading both output and error filehandles sametime $self->{'selector'} = IO::Select->new(); $self->{inputfh} = IO::Handle->new(); $self->{outputfh} = IO::Handle->new(); $self->{errorfh} = IO::Handle->new(); { $self->{pid} = open3($self->{inputfh}, $self->{outputfh}, $self->{errorfh}, $cmd_to_exe); $self->{'selector'}->add($self->{inputfh}, $self->{outputfh}, $self->{errorfh} ); #print $self->{pid}; return (1); } } sub canSendInput { my $self = shift; my $pid = waitpid($self->{pid}, WNOHANG); #print $pid; #return $pid; ($pid==0)?return(1):return(0); } #Sending input to command by printing in the input file handler sub sendInput { my $self = shift; my @input = @_; if(canSendInput($self)) { my $kid = waitpid($self->{pid}, WNOHANG); foreach my $input(@input) { (print {$self->{inputfh}} "$input") or return (0); return (1); } } } #Retriving output of the command executed for the last input sub getOutput { my $self = shift; my $errCall = shift; my $outputfh = $self->{outputfh}; my $errorfh = $self->{errorfh}; my $output = ""; my $error = ""; my @ready = $self->{selector}->can_read(1); foreach my $fh ( @ready ) { while(sysread($fh, my $text, 1024)) #Reading 1024 bytes in every iteration { if(fileno($fh) == fileno($outputfh)) { $output.= $text; #print $text; last if(length($text) < 1024); } else { $error.= $text; #print $text; last if(length($text) < 1024); } } } #Returning only Error when getOutput is called from getError() and saving output text into object so we can use it later if($errCall) { $self->{stdout} = $output; $error.=$self->{stderr}; # Updating errors which are not returned so far $self->{stderr} = ""; return $error; } #Returning only Output when getOutput is called directly after saving error text into object so we can use it later else{ $self->{stderr} = $error; $output.=$self->{output}; # Updating output which are not returned so far $self->{stdout}=""; return $output; } } #Retriving error sub getError { my $self = shift; my $error = getOutput($self, 1); return $error; } sub stop { my $self = shift; if( defined( $self->{'selector'} ) ) { $self->{'selector'}->remove( $self->{inputfh}, $self->{outputfh}, $self->{errorfh} ); } local $SIG{INT} = 'IGNORE'; kill INT => -$$; } #Destructor sub DESTROY { my $self = shift; &stop; } 1;