Убить процесс из сценария Perl

Я пытаюсь убить процесс по имени, который я передам в качестве переменной системной команде.

Ниже то, что у меня есть:

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

Приведенный выше скрипт выдает ошибку:

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

Однако, если я непосредственно ввожу имя процесса в системную команду, это работает.

Может ли кто-нибудь помочь мне в этом?

4 ответа

Одна из проблем заключается в том, что в командной строке, которая вызывает скрипт, есть имя процесса, который вы затем запрашиваете, по своему замыслу; так что одна найденная вещь будет сам скрипт.

От этого можно защититься, но зачем выходить в систему с таким большим конвейером?

Запросите процесс в Perl, например, с помощью Proc::ProcessTable

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

my $proc_name = shift @ARGV or 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;
    }   
}

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

Обратите внимание, что гораздо приятнее "убить" процесс, отправив его SIGTERM (обычно 15), а не SIGKILL,

Поиск "имени" процесса может быть опасным, так как в современной системе работает много процессов с длинными командными строками, которые могут содержать это слово. Код использует ваше требование, чтобы просто выполнить запрос по представленному имени, но я рекомендую усилить это дополнительными проверками.

Для многих деталей процесса, которые модуль может запросить, смотрите его заглушки.

Даже если вы захотите разобрать таблицу процессов самостоятельно, я получу только ps -ef а затем разобрать его в сценарии. Это дает гораздо больше гибкости в обеспечении того, что вы действительно прекратить то, что вы хотите.

У вас есть разные переменные $processName а также $jobName так что весь ` ` выражение заканчивается пустым. use strict указал бы на это; это полезно даже для трехстрочных сценариев. kill сообщение об ошибке - это то, что вы получаете, когда запускаете его без каких-либо аргументов.

Pro совет: pkill существует, вы можете заменить весь проблемный взлом одной командой.

my $pid = `ps -ef | grep '$processName' | grep -v grep | awk '{print \$2}'`;
print $pid;
system("kill -9 $pid");

Этот работает!!!

Вы можете убить процесс по имени, не вызывая оболочку, используя IPC::System::Simple:

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

Или вы можете сначала собрать список идентификаторов процессов:

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

Тогда вам не нужно беспокоиться о String::ShellQuote, Посмотрите на этот ответ Даксим.

Другие вопросы по тегам