4

I am trying to kill a process by name which i will pass as a variable to a system command.

Below is what i have:

my $processName=$ARGV[0];
print "$processName\n";
system(q/kill -9 `ps -ef | grep '$processName' | grep -v grep | awk '{print $2}'`/);

The above script throws an error:

kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]

However, if i directly enter the process name inside the system command, it works.

Can someone help me on this?

blackfury
  • 675
  • 3
  • 11
  • 22
  • 2
    The `$processName` doesn't get interpolated within `q//`. This means you're grepping for literal `dollar`-`p`-`r`-`o`-`…` which eventually returns nothing. – PerlDuck Mar 20 '18 at 10:58

4 Answers4

10

One problem is that the command line that invokes the script has the name of the process which you then query, by design; so one thing found will be the script itself.

This can be guarded against, but why go out to the system with that big pipeline?

Query the process in Perl, for example with Proc::ProcessTable

use warnings;
use strict;
use Proc::ProcessTable;

my $proc_name = shift // die "Usage: $0 process-name\n";  #/

my $pid;
my $pt = Proc::ProcessTable->new();
foreach my $proc (@{$pt->table}) {
    next if $proc->cmndline =~ /$0.*$proc_name/;  # not this script
    if ($proc->cmndline =~ /\Q$proc_name/) {
        $pid = $proc->pid;
        last;
    }   
}
die "Not found process with '$proc_name' in its name\n" if not defined $pid;    

kill 9, $pid;                    # must it be 9 (SIGKILL)? 
my $gone_pid = waitpid $pid, 0;  # then check that it's gone

Note that it is far nicer to "kill" a process by sending it SIGTERM (usually 15), not SIGKILL.

Looking for a process "name" can be perilous as there are many processes with long command lines running on a modern system that may contain that word. The code uses your requirement, to simply query by submitted name, but I recommend strengthening that with additional checks.

For many process details that the module can query see its stub module.

Even if you'd rather parse the process table yourself I would get only ps -ef and then parse it in the script. That gives far more flexibility in ensuring that you really terminate what you want.

zdim
  • 64,580
  • 5
  • 52
  • 81
2

You have the different variables $processName and $jobName, so the whole ` ` expression ends up empty. use strict would have pointed that out; it's useful even for three-line scripts. The kill error message is what you get when you run it without any arguments.

Pro tip: pkill exists, you can replace the whole problematic hack with one command.

daxim
  • 39,270
  • 4
  • 65
  • 132
1
my $pid = `ps -ef | grep '$processName' | grep -v grep | awk '{print \$2}'`;
print $pid;
system("kill -9 $pid");

This one works!!!

blackfury
  • 675
  • 3
  • 11
  • 22
  • The `$processName` is present in the command that invokes your script (`script proc-name` or such) and your pipeline finds that, too. The actual process should be listed before the script but you _are_ relying on that. – zdim Mar 20 '18 at 09:19
  • 2
    No point having this as a perl script when it might as well be just a regular shell script. – Chris Turner Mar 20 '18 at 09:50
  • @ChrisTurner: Since the initial question is how to kill a process from within Perl, the choice of using a shell script instead seems to be in conflict with the premise of the question. There are problems associated with this answer, but the fact that it's done from within Perl is not one of them. (E.g.: Use `pgrep` instead; don't pipe user input directly into backticks.) – sshine Mar 20 '18 at 10:35
  • Did you know Perl has a built-in function [`kill`](http://perldoc.perl.org/functions/kill.html)? No need to shell-out. – PerlDuck Mar 20 '18 at 11:00
0

You can kill a process by name without invoking the shell by using IPC::System::Simple:

use IPC::System::Simple qw(systemx EXIT_ANY);
systemx(EXIT_ANY, 'pkill', '-9', '--', $processName);

Or you can collect a list of process IDs first:

use IPC::System::Simple qw(capturex EXIT_ANY);
kill 9, capturex(EXIT_ANY, 'pgrep', '--', $processName));

Then you don't have to worry about String::ShellQuote. See this answer by daxim.

sshine
  • 15,635
  • 1
  • 41
  • 66