Я пытаюсь убить процесс по имени, которое передам как переменную системной команде.
Вот что у меня есть:
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 и $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 или подобный), и ваш конвейер тоже это обнаруживает. Фактический процесс должен быть указан перед сценарием, но вы полагаетесь на это находятся.
Нет смысла использовать это как сценарий Perl, хотя это может быть и обычный сценарий оболочки.
@ChrisTurner: Поскольку первоначальный вопрос заключается в том, как убить процесс из Perl, выбор использования вместо этого сценария оболочки, похоже, вступает в конфликт с предпосылкой вопроса. С этим ответом связаны проблемы, но тот факт, что это делается из Perl, не входит в их число. (Например: вместо этого используйте pgrep; не перенаправляйте ввод пользователя напрямую в обратные кавычки.)
Вы можете убить процесс по имени, не вызывая оболочку, используя 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.
$processNameне интерполируется вq//. Это означает, что вы ищете буквальныйdollar-p-r-o-…, который в конечном итоге ничего не возвращает.