2

I have written a Perl script to run some given commands through the script.

system("my_command");

After running my Perl script, the "my_command" is starting on the Linux terminal properly. Later, I killed my script using 'ctrl+z; kill %%'. but the "my_command" is still running. I tried 'kill %%' again several times but the "my_command" did not terminate. ("my_command" is another Perl script that working properly).

What I need is, if I terminate the initial Perl script/runner then all commands that have been started using 'system()' should be terminated.

Is there any way to achieve this.?

1 Answer 1

4

system isn't so useful for this. Consider using open2 which returns the process identifier for the started child process.

use IPC::Open2;

# A system() like call using open2():

my $pid = open2('>&STDOUT', '<&STDIN', @CommandLine);

You can now kill and waitpid on $pid.

Here's an example using some old school OOP so that all the processes you've started will be killed automatically when your program exits. I'm sure there are ready perl packages encapsulating this in a more complete fashion, but this should give you the general idea.

#!/usr/bin/perl

use strict;
use warnings;

package mysystem;

use IPC::Open2;

sub new {
    my $class=shift;

    bless {
        'pid' => open2('>&STDOUT', '<&STDIN', @_)
    }, $class;
}

sub DESTROY {
    my $self = shift;
    $self->kill(15);  # or whatever signal you want to send to it
    $self->wait;
    print "DEBUG PRINTOUT: DONE\n";
}

sub wait {
    # wait for the process to terminate
    my $self = shift;
    waitpid($self->{pid}, 0);
}

sub kill {
    # send a signal to the process
    my ($self, $signal) = @_;
    kill($signal, $self->{pid});
}

sub alive {
    # check if the process is alive
    my $self = shift;
    $self->kill(0) == 1;
}

sub run {
    # do like system(), start a sub process and wait for it
    my $sys = new(@_);
    $sys->wait;
}

package main;

sub handler {
    print "Caught signal @_ - exiting\n";
    exit(0);
}

$SIG{INT} = \&handler;

my $proc = mysystem->new('sleep', '1000');
print "Pid ". $proc->{pid} . " is " . ($proc->alive()?"alive":"dead") . "\n";

print "Letting the destructor kill it\n";

Possible output:

Pid 3833402 is alive
Letting the destructor kill it
DEBUG PRINTOUT: DONE
Sign up to request clarification or add additional context in comments.

5 Comments

This doesn't actually answer the question on how to terminate system()-spawned commands. The answer only says not to use system().
@KubaFYI Yes, instead of trying explain how to use a hammer to screw in a screw I provided a saner alternative for OPs case.
Yeah it makes sense. I'm just grumpy it didn't help me with my issue of having to kill stuff spawned with system in thousands of lines of code written by someone else, now long gone haha
@KubaFYI :-) What's the setup? system("command &"); or something? Perhaps if you describe what the script does in a minimal reproducible example in a new question I can have a look. The easiest is probably to replace the system calls with myspawn and then do a little fork() magic that keeps track of all the spawned pids - but, need to now a little more detail.
There's probably like 5 different ways in which children processes are being spawned in that codebase, so it's probably not worth getting into it here in the comments. Thanks for the offer of help tho!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.