Как я могу быстро найти PID терминала пользователя в Perl?

Следующий фрагмент кода используется для поиска 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 или искажение результатов? Это поможет избежать оптимизации того, что на самом деле не имеет никакого значения.

The Archetypal Paul 26.12.2008 15:11

ptree замедляет работу программы. Никаких сомнений насчет этого. Мне просто интересно, есть ли лучший способ уловить идентификатор процесса в третьей строке результатов ptree. Это все, что мне нужно от этого кода.

lamcro 26.12.2008 16:06

То, как вы ловите PID, выглядит разумным. Единственная (микро) оптимизация заключается в том, что вы знаете, что регулярное выражение не будет соответствовать первым двум строкам. Вы можете просто сосчитать три строки, а затем сопоставить регулярное выражение только с третьей. Однако, учитывая, что время указано в ptree, в чем смысл? Смотрите мой другой ответ.

The Archetypal Paul 26.12.2008 17:04
Стоит ли изучать 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
3
1 806
6

Ответы 6

Думаю, основная проблема в том, что этот код зациклен. Вам не нужно запускать ptree и анализировать результаты более одного раза! Вам нужно найти способ запустить ptree один раз и поместить его в структуру данных, которую вы сможете использовать позже. Наверное хватит какого-нибудь простого хеша. Возможно, вы даже сможете просто сохранить хэш% терминалов и продолжать его повторно использовать.

Некоторые придирки ...

  • Оба ваших "следующих" утверждения кажутся мне не нужно ... ты должен быть возможность их просто удалить.

  • Заменять

    $terminals{$user} = $terminals{$user} . " $1";
    

с участием:

    $terminals{$user} .= " $1";
  • Замените открытое слово PTREE, которое вы используются в качестве дескриптора файла с $ ptreeF или что-то в этом роде ... используя голые слова стали ненужными для файловые ручки лет 10 назад :)

  • Я не знаю, почему ваша переменная $ PID все заглавные буквы ... это может сбивать с толку читателям вашего кода, потому что он похоже, что есть что-то особенный об этой переменной, и нет.

AFAICT, ptree вызывается каждый раз в цикле с разными аргументами.

The Archetypal Paul 26.12.2008 16:00

Верный. ptree вызывается разное время в цикле.

lamcro 26.12.2008 16:07

Спасибо за придирки, ДжоэлФан. Я не использовал Perl более 10 лет, поэтому любые изменения после этого мне чужды. Я снова в значительной степени новичок.

lamcro 26.12.2008 16:10

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

JoelFan 26.12.2008 17:15

Я думаю, что вы получите лучшее повышение производительности, если избежите накладных расходов, связанных с повторным выполнением внешней команды (в данном случае ptree). Я бы поискал модуль CPAN, который предоставляет прямой интерфейс к структурам данных, которые читает ptree. Может быть, проверить пространство имен Linux ::? (Я не уверен, что ptree - это Setuid; это может усложнить ситуацию.)

Помимо приведенного выше совета, некоторые дополнительные примечания к стилю и надежности, основанные только на опубликованном фрагменте (простите меня, если более крупный код делает их недействительными):

  • Я бы начал, по крайней мере, с strict. Лексические дескрипторы файлов тоже будет хорошей идеей.

  • Похоже, вы молча игнорируете случай, когда вы не можете open() команду ptree. Это могло произойти по многим причинам, некоторые из которых я не могу себе представить, чтобы вы проигнорировали их, например…

  • Вы не используете полный путь к команде ptree, а скорее предполагаете, что он находится на вашем пути, и что тот, который находится на вашем пути, является правильным.

Я думал использовать ps, чтобы получить pid родителей, но мне нужно было бы зациклить это, чтобы получить pid прадеда. Это то, что мне нужно. Спасибо.

lamcro 26.12.2008 19:26

Сколько пользователей в системе? Вы можете это перевернуть? Перечислите все процессы -pksh-ksh в системе вместе с их EUID и создайте карту из этого - это может быть только одно выполнение ps / ptree.

К сожалению, пользователей много, и у каждого может быть открыто до трех терминалов. Весь сценарий используется для поиска тех терминалов, которые используют файл. Я использую фьюзер, чтобы найти процессы, использующие файл. Затем используйте ptree, чтобы найти pid терминала.

lamcro 26.12.2008 17:32

Готов поспорить, что с помощью одного ps получение данных для всех процессов будет намного быстрее, и я не вижу реальной проблемы с количеством пользователей.

ysth 27.12.2008 00:46

Я просто сделал несколько тривиальных таймингов на основе вашего скрипта (вызвав «cat ptree.txt» вместо самого ptree) и подтвердил свои мысли о том, что все ваше время тратится на создание новых подпроцессов и запуск самого ptree. Если вы не сможете исключить необходимость вызова ptree (возможно, есть способ открыть соединение один раз и повторно использовать его, как с nslookup), вы не увидите никаких реальных преимуществ.

Рассматривали ли вы использование who -u, чтобы сообщить вам, какой процесс является оболочкой входа в систему для данного tty, вместо использования ptree? Это упростит ваш поиск, независимо от других изменений, которые вам также придется внести.

Спасибо, но терминальных процессов слишком много, и мне нужно найти те, которые используют файл.

lamcro 26.12.2008 19:22

Я думал использовать 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

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