Следующий фрагмент кода используется для поиска PID пользовательского терминала с помощью ptree и получения PID в третьих из результатов, которые он возвращает. Все PID терминала хранятся в хэше с логином пользователя в качестве ключа.
## If process is a TEMINAL.
## The command ptree is used to get the terminal's process ID.
## The user can then use this ID to peek the user's terminal.
if ($PID =~ /(\w+)\s+(\d+) .+basic/) {
$user = $1;
if (open(PTREE, "ptree $2 |")) {
while ($PTREE = <PTREE>) {
if ($PTREE =~ /(\d+)\s+-pksh-ksh/) {
$terminals{$user} = $terminals{$user} . " $1";
last;
}
next;
}
close(PTREE);
}
next;
}
Ниже приведен пример выполнения ptree:
ares./home_atenas/lmcgra> ptree 29064
485 /usr/lib/inet/inetd start
23054 /usr/sbin/in.telnetd
23131 -pksh-ksh
26107 -ksh
29058 -ksh
29064 /usr/ob/bin/basic s=61440 pgm=/usr/local/etc/logon -q -nr trans
412 sybsrvr
Я хотел бы знать, есть ли лучший способ кодировать это. Это часть сценария, выполнение которой занимает больше всего времени.
Примечание: этот код вместе с другими фрагментами находится внутри цикла и выполняется несколько раз.
ptree замедляет работу программы. Никаких сомнений насчет этого. Мне просто интересно, есть ли лучший способ уловить идентификатор процесса в третьей строке результатов ptree. Это все, что мне нужно от этого кода.
То, как вы ловите PID, выглядит разумным. Единственная (микро) оптимизация заключается в том, что вы знаете, что регулярное выражение не будет соответствовать первым двум строкам. Вы можете просто сосчитать три строки, а затем сопоставить регулярное выражение только с третьей. Однако, учитывая, что время указано в ptree, в чем смысл? Смотрите мой другой ответ.





Думаю, основная проблема в том, что этот код зациклен. Вам не нужно запускать ptree и анализировать результаты более одного раза! Вам нужно найти способ запустить ptree один раз и поместить его в структуру данных, которую вы сможете использовать позже. Наверное хватит какого-нибудь простого хеша. Возможно, вы даже сможете просто сохранить хэш% терминалов и продолжать его повторно использовать.
Некоторые придирки ...
Оба ваших "следующих" утверждения кажутся мне не нужно ... ты должен быть возможность их просто удалить.
Заменять
$terminals{$user} = $terminals{$user} . " $1";
с участием:
$terminals{$user} .= " $1";
Замените открытое слово PTREE, которое вы используются в качестве дескриптора файла с $ ptreeF или что-то в этом роде ... используя голые слова стали ненужными для файловые ручки лет 10 назад :)
Я не знаю, почему ваша переменная $ PID все заглавные буквы ... это может сбивать с толку читателям вашего кода, потому что он похоже, что есть что-то особенный об этой переменной, и нет.
AFAICT, ptree вызывается каждый раз в цикле с разными аргументами.
Верный. ptree вызывается разное время в цикле.
Спасибо за придирки, ДжоэлФан. Я не использовал Perl более 10 лет, поэтому любые изменения после этого мне чужды. Я снова в значительной степени новичок.
np ... на самом деле, второй "следующий" может быть необходим, потому что он, вероятно, выходит из внешнего цикла, который вы не показываете
Я думаю, что вы получите лучшее повышение производительности, если избежите накладных расходов, связанных с повторным выполнением внешней команды (в данном случае ptree). Я бы поискал модуль CPAN, который предоставляет прямой интерфейс к структурам данных, которые читает ptree. Может быть, проверить пространство имен Linux ::? (Я не уверен, что ptree - это Setuid; это может усложнить ситуацию.)
Помимо приведенного выше совета, некоторые дополнительные примечания к стилю и надежности, основанные только на опубликованном фрагменте (простите меня, если более крупный код делает их недействительными):
Я бы начал, по крайней мере, с strict. Лексические дескрипторы файлов тоже будет хорошей идеей.
Похоже, вы молча игнорируете случай, когда вы не можете open() команду ptree. Это могло произойти по многим причинам, некоторые из которых я не могу себе представить, чтобы вы проигнорировали их, например…
Вы не используете полный путь к команде ptree, а скорее предполагаете, что он находится на вашем пути, и что тот, который находится на вашем пути, является правильным.
Я думал использовать ps, чтобы получить pid родителей, но мне нужно было бы зациклить это, чтобы получить pid прадеда. Это то, что мне нужно. Спасибо.
Сколько пользователей в системе? Вы можете это перевернуть? Перечислите все процессы -pksh-ksh в системе вместе с их EUID и создайте карту из этого - это может быть только одно выполнение ps / ptree.
К сожалению, пользователей много, и у каждого может быть открыто до трех терминалов. Весь сценарий используется для поиска тех терминалов, которые используют файл. Я использую фьюзер, чтобы найти процессы, использующие файл. Затем используйте ptree, чтобы найти pid терминала.
Готов поспорить, что с помощью одного ps получение данных для всех процессов будет намного быстрее, и я не вижу реальной проблемы с количеством пользователей.
Я просто сделал несколько тривиальных таймингов на основе вашего скрипта (вызвав «cat ptree.txt» вместо самого ptree) и подтвердил свои мысли о том, что все ваше время тратится на создание новых подпроцессов и запуск самого ptree. Если вы не сможете исключить необходимость вызова ptree (возможно, есть способ открыть соединение один раз и повторно использовать его, как с nslookup), вы не увидите никаких реальных преимуществ.
Рассматривали ли вы использование who -u, чтобы сообщить вам, какой процесс является оболочкой входа в систему для данного tty, вместо использования ptree? Это упростит ваш поиск, независимо от других изменений, которые вам также придется внести.
Спасибо, но терминальных процессов слишком много, и мне нужно найти те, которые используют файл.
Я думал использовать ps, чтобы получить pid родителей, но мне нужно было бы зациклить это, чтобы получить pid прадеда. Это то, что мне нужно. Спасибо. - Ламкро
К сожалению, пользователей много, и у каждого может быть открыто до трех терминалов. Весь сценарий используется для поиска тех терминалов, которые используют файл. Я использую фьюзер, чтобы найти процессы, использующие файл. Затем используйте ptree, чтобы найти pid терминала. - Ламкро
Если у вас есть (или вы можете получить) список PID с помощью файла, и вам просто нужны все прародители этого PID, наверняка есть более простой способ.
#!perl
use warnings;
use strict;
#***** these PIDs are gotten with fuser or some other method *****
my($fpids) = [27538, 31812, 27541];
#***** get all processes, assuming linux PS *****
my($cmd) = "ps -ef";
open(PS, "$cmd |") || die qq([ERROR] Cannot open pipe from "$cmd" - $!\n);
my($processlist) = {};
while (<PS>) {
chomp;
my($user, $pid, $ppid, $rest) = split(/ +/, $_, 4);
$processlist->{$pid} = $ppid;
}
close PS;
#***** lookup grandparent *****
foreach my $fpid (@$fpids) {
my($parent) = $processlist->{$fpid} || 0;
my($grandparent) = $processlist->{$parent} || 0;
if ($grandparent) {
#----- do something here with grandparent's pid -----
print "PID:GRANDPID - $fpid:$grandparent\n";
}
else {
#----- some error condition -----
print "ERROR - Cannot determine GrandPID: $fpid ($parent)\n";
}
}
Что для меня производит:
ERROR - Cannot determine GrandPID: 27538 (1)
PID:GRANDPID - 31812:2804
PID:GRANDPID - 27541:27538
«Это часть сценария, выполнение которой занимает больше всего времени». Какая часть этого требует времени? Выполнение ptree или искажение результатов? Это поможет избежать оптимизации того, что на самом деле не имеет никакого значения.