Search code examples
perlperl-ioperl-ipc-run

perl open() always returns the PID of the sh instead of the underlying program


I have to kill a program that I am opening via

$pid = open(FH, "program|")

or

$pid = or open(FH, "-|", "program")

However, the program (mosquittto_sub, to be specific) still lingers around in the background, because open is returning the PID of the sh that perl is using to run the program, so I am only killing the sh wrapper instead of the actual program.

Is there a way to get the programs real PID? What is the point of getting the sh's PID?


Solution

  • There are a few ways to deal with this.

    First, you can use a list form to open a process and then no shell is involved so the child process (with pid returned by open) is precisely the one with the program you need to stop

    my @cmd = ('progname', '-arg1', ...);
    
    my $pid = open my $fh, '-|', @cmd  // die "Can't open \"@cmd\": $!";
    
    ...
    
    my $num_signaled = kill 15, $pid;
    

    This sketch needs some checks added. Please see the linked documentation (look for "pipe").

    If this isn't suitable for some reason -- perhaps you need the shell to run that program -- then you can find the program's pid, and Proc::ProcessTable module is good for this. A basic demo

    use Proc::ProcessTable;
    
    my $prog_name = ...
    
    my $pid;
    my $pt = Proc::ProcessTable->new();
    
    foreach my $proc (@{$pt->table}) {
        if ($proc->cmndline =~ /\Q$prog_name/) {  # is this enough to identify it?
            $pid = $proc->pid;
            last;
        }   
    }
    my $num_signaled = kill 15, $pid;
    

    Please be careful with identifying the program by its name -- on a modern system there may be all kinds of processes running that contain the name of the program you want to terminate. For more detail and discussion please see this post and this post, for starters.

    Finally, you can use a module to run your external programs and then you'll be able to manage and control them far more nicely. Here I'd recommend IPC::Run.