Убить процесс из 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]

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

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

$processName не интерполируется в q//. Это означает, что вы ищете буквальный dollar-p-r-o-, который в конечном итоге ничего не возвращает.

PerlDuck 20.03.2018 11:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
1
5 209
4

Ответы 4

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

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

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

Этого можно избежать, но зачем выходить в систему с таким большим трубопроводом?

Запросите процесс в Perl, например, с помощью 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

Обратите внимание, что гораздо лучше «убить» процесс, отправив ему SIGTERM (обычно 15), а не SIGKILL.

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

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

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

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

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

$processName присутствует в команде, которая вызывает ваш скрипт (script proc-name или подобный), и ваш конвейер тоже это обнаруживает. Фактический процесс должен быть указан перед сценарием, но вы полагаетесь на это находятся.

zdim 20.03.2018 10:19

Нет смысла использовать это как сценарий Perl, хотя это может быть и обычный сценарий оболочки.

Chris Turner 20.03.2018 10:50

@ChrisTurner: Поскольку первоначальный вопрос заключается в том, как убить процесс из Perl, выбор использования вместо этого сценария оболочки, похоже, вступает в конфликт с предпосылкой вопроса. С этим ответом связаны проблемы, но тот факт, что это делается из Perl, не входит в их число. (Например: вместо этого используйте pgrep; не перенаправляйте ввод пользователя напрямую в обратные кавычки.)

Simon Shine 20.03.2018 11:35

Знаете ли вы, что Perl имеет встроенную функцию kill? Не нужно раскошеливаться.

PerlDuck 20.03.2018 12:00

Вы можете убить процесс по имени, не вызывая оболочку, используя 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. Смотрите этот ответ от daxim.

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