Убить процесс из сценария 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
, Посмотрите на этот ответ Даксим.