Perl closing pipe without errors

I am using Perl to execute an external program and would like to end it if it returns a specific line at runtime. The code below interrupts execution as desired, however, an error message is returned when the last line is executed (closing).

open (my $out, "-|", "usfos $memory<input-$cpu.scr");
while (<$out>) {
    if ($_ =~ /MIN   STEP  LENGTH/) {
        last;
    }
}
close $out;

This is part of the error being printed (the external program also returns error messages):

...forrtl: The pipe is being closed.
forrtl: severe (38): error during write, unit 6, file CONOUT$

So, I think this is because Perl is trying to write a closed descriptor. How can I avoid printing?

+1
source share
1 answer

You do not shut down an external program when close $out, you close it STDOUT.

, . open pid, . , .

use Scalar::Util qw(openhandle); # to check whether the handle is open

my $pid = open (my $out, "-|", "usfos $memory<input-$cpu.scr") 
                // die "Can't fork: $!";   # / stop editor red coloring
while (<$out>) {
    if (/MIN   STEP  LENGTH/) {
        kill "TERM", $pid;   # or whatever is appropriate; add checks
        close $out;          # no check: no process any more so returns false
        last;
    }
}
# Close it -- if it is still open. 
if (openhandle($out)) {          
    close $out or warn "Error closing pipe: $!";
}

open opentut, close.

Fortran (STDOUT), , : (last) STDOUT, .

. . , close, $? . SIGPIPE . close

, close false, . , , $! 0. , - , - $? $ {^ CHILD_ERROR_NATIVE}.
...
, , SIGPIPE. , .


, , STDOUT , ( ). , , SIGPIPE , , , . ( ?) , , close($out) , , $out .

close , ( kill ). , , , , . Scalar::Util, - fileno. , , kill , .


Windows , . , , Win32::Process::Kill, kill. ( . Windows, , .) ,

  • Win32::Process::List

    use Win32::Process::Kill;
    use Win32::Process::List;
    my $pobj = Win32::Process::List->new(); 
    my %proc = $pobj->GetProcesses(); 
    my $exitcode;
    foreach my $pid (sort { $a <=> $b } keys %proc) {
        my $name = $proc{$pid};
        if ($name =~ /usfos\.exe/) {
            Win32::Process::KillProcess($pid, \$exitcode);
            # kill 21, $pid;
            last;
        }
     }
    
  • Win32::Process::Info. .

    use Win32::Process::Info;
    Win32::Process::Info->Set(variant=>'WMI');   # SEE DOCS about WMI
    my $pobj = Win32::Process::Info->new();
    foreach my $pid ($pobj->ListPids) {
        my ($info) = $pobj->GetProcInfo($pid);
        if ($info->{CommandLine} =~ /^usfso/) {  # command-line, not name
            my $proc = $info->{ProcessId};
            kill 2, $proc; 
            last;
        }
    }
    

    , Subprocesses([$ppid,...]), $ppid (s). , $ppid -ref $pid $ppid.

    use Win32::Process::Info;
    Win32::Process::Info->Set(variant=>'WMI');
    my $pobj = Win32::Process::Info->new();
    my %subproc = $pobj->Subprocesses([$pid]);   # pid returned by open() call
    my $rkids = $subproc{$pid};
    foreach my $kid (@$rkids) {
        print "pid: $kid\n";                     # I'd first check what is there
    }
    
  • Windows TASKKILL/T TASKKILL/T

    system("TASKKILL /F /T /PID $pid");
    

.

+4

All Articles