perlipcopen3

IPC::open3 error handling with out select


The below code is working fine but i want to achieve same thing without using IO::Select - I tried few things but nothing works, as I am not much familiar with perl.

sub writeTologs
{
my $cmd=shift;

open(ERRLOG, '>>log//error.log') or die "Can't open error log! $!";
open(OUTPUT, '>>log//output.log') or die "Can't open output log! $!";

my ($infh,$outfh,$errfh); # these are the FHs for our child
$errfh = gensym(); # we create a symbol for the errfh   # because open3 will not do that for us

my $pid;
               #
eval{
$pid = open3($infh, $outfh, $errfh, $cmd);
};
die "open3: $@\n" if $@;
               #
print "PID was $pid\n";


my $sel = new IO::Select; # create a select object to notify
                      # us on reads on our FHs (File Handlers)
$sel->add($outfh,$errfh); # add the FHs we're interested in
                      #
    while(my @ready = $sel->can_read) { # read ready
            foreach my $fh (@ready) {
                    my $line = <$fh>; # read one line from this fh
                    if(not defined $line){ # EOF on this FH
                    $sel->remove($fh); # remove it from the list
                    next;              # and go handle the next FH
                    }

                    if($fh == $outfh) {     # if we read from the outfh
                            print OUTPUT $line; # print it to OUTFH
                    }
                    elsif($fh == $errfh) {# do the same for errfh
                            print ERRLOG $line;
                            die "Error found : $@";
                            }
                            else { # we read from something else?!?!
                                    die "Shouldn't be here\n";
                            }
                    }
    }

close(ERRLOG) or die "Can't close filehandle! $!";
close(OUTPUT) or die "Can't close filehandle! $!";

 }

I want to die my process after writing to ERRLOG .

I have tried below code-

open(ERRLOG, '>>log//error.log') or die "Can't open error log! $!";
open(OUTPUT, '>>log//output.log') or die "Can't open output log! $!";

my ($infh,$outfh,$errfh); # these are the FHs for our child
$errfh = gensym(); # we create a symbol for the errfh   # because open3 will not do that for us

my $pid;
my $line="";                   #
eval{
$pid=open3($infh, $outfh, $errfh, $cmd1);
};
die "open3: $@\n" if $@;

if (defined(<$errfh>)) {
        print "Error start ".<$errfh>;
        $errfh->close;
        while($line = <$errfh>) {
                print $line;
                print "Inside while";
        }

        print "Error deifned \n";
} else {

        while ($line=<$outfh>) {
                print OUTPUT $line;
        }
        print "Output log";
}

But while loop is not getting executed inside the if condition.


Solution

  • I was able to achieve this from below code -

    sub writeTologs {
    my $cmd      = shift;
    my $strout   = "$LOGDIR/$STDLOG";
    my $strerr   = "$LOGDIR/$ERRORLOG";
    my $flag     = 0;
    my $line     = '';
    my $pid;
    
    open(ERRLOG   , '>>', $strerr  ) or die "Can't open error log! $!";
    open(SCHDLOG , '>>', $strout  ) or die "Can't open output log! $!";
    
    my ($infh,$outfh,$errfh);
    $errfh = gensym();
    
    eval
    {
        $pid = open3($infh, $outfh, $errfh, $cmd);
    };
    die "Open faile : $@" if $@;
    
    my $line_err  = <$errfh>;
    
    if (defined(<$outfh>))
    {
        while($line = <$outfh>)
        {
                print SCHDLOG '[' . get_timestamp() . "]: $line";
        }
    }
    
    if ($line_err)
    {
        print ERRLOG $line_err;
        $flag =1 ;
    }
    
    print "PID = $pid";
    
    waitpid($pid,0);
    
    close(ERRLOG)  or die "Can't close filehandle! $!";
    close(SCHDLOG) or die "Can't close filehandle! $!";
    return $flag;
    }