【问题标题】:How can I quickly find the user's terminal PID in Perl?如何在 Perl 中快速找到用户的终端 PID?
【发布时间】:2010-09-28 11:05:06
【问题描述】:

下面的 sn-p 代码用于查找用户终端的 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

我想知道是否有更好的编码方式。这是脚本中运行时间最长的部分。

注意:这段代码和其他 sn-ps 都在一个循环中并被执行了几次。

【问题讨论】:

  • "这是脚本中运行时间最长的部分。"哪一点需要时间? ptree 的执行,还是结果的修改?这将有助于避免优化实际上没有任何区别的东西。
  • ptree 会减慢程序的速度。毫无疑问。我只是想知道是否有更好的方法来捕获 ptree 结果中第三行中的进程 ID。这就是我从这段代码中需要的全部内容。
  • 捕获 PID 的方式看起来很合理。唯一的(微)优化是您知道正则表达式与前两行不匹配。您可以只数三行,然后仅在第三行上进行正则表达式匹配。但是,鉴于时间在 ptree 中,有什么意义呢?请参阅我的其他答案。

标签: perl terminal pid


【解决方案1】:

我认为主要问题是这段代码处于循环中。您无需多次运行 ptree 并解析结果!您需要想出一种方法来运行一次 ptree 并将其放入以后可以使用的数据结构中。可能是某种简单的哈希就足够了。您甚至可以只保留 %terminals 哈希值并继续重复使用它。

一些吹毛求疵...

  • 你的两个“下一个”陈述似乎 对我来说没必要……你应该是 可以删除它们。

  • 替换

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

与:

    $terminals{$user} .= " $1";
  • 替换您使用的裸词 PTREE 用作文件句柄 $ptreeF 或类似的...使用 空话变得不必要了 大约 10 年前的文件句柄 :)

  • 我不知道为什么你的 $PID 变量 全部大写...这可能会令人困惑 给你的代码的读者,因为它 好像有什么东西 特别是那个变量,和 没有。

【讨论】:

  • AFAICT,ptree 每次在循环中使用不同的参数调用。
  • 正确。 ptree 在循环中的不同时间被调用。
  • 感谢 JoelFan 的挑剔。我已经 10 多年没有使用 perl 了,所以之后的任何更改对我来说都是陌生的。我又是个菜鸟了。
  • np... 实际上,第二个“下一个”可能是必要的,因为它可能会从您未显示的外部循环中转义
【解决方案2】:

我认为通过避免重复执行外部命令(在本例中为ptree)的开销,您将获得最佳的性能提升。我会寻找一个 CPAN 模块,它为ptree 正在读取的数据结构提供直接接口。检查Linux:: 命名空间,也许? (我不确定ptree 是不是setuid;这可能会使事情复杂化。)

除了上面的建议,一些额外的样式和健壮性注释仅基于发布的 sn-p(如果更大的代码使它们无效,请原谅我):

  • 至少我会从使用strict 开始。 Lexical filehandles 也是个好主意。

  • 当你不能open()ptree 命令时,你似乎默默地忽略了这种情况。发生这种情况的原因有很多,其中一些我无法想象你会想忽略,例如……

  • 您没有使用ptree 命令的完整路径,而是假设它在您的路径中——并且您路径中的路径是正确的。

【讨论】:

  • 我正在考虑使用 ps 来获取父母的 pid,但我需要循环这个来获取曾祖父母的 pid。那是我需要的。谢谢。
【解决方案3】:

系统上有多少用户?你能把这个倒过来吗?列出系统中的所有 -pksh-ksh 进程及其 EUID,并从中构建映射 - 这可能只是 ps/ptree 的一次执行。

【讨论】:

  • 对不起,有很多用户,每个人最多可以打开三个终端。整个脚本用于查找正在使用文件的终端。我使用 fuser 来查找使用文件的进程。然后使用 ptree 查找终端的 pid。
  • 我敢打赌,单个 ps 获取所有进程的数据会快得多,而且我看不出用户数量存在任何实际问题。
【解决方案4】:

我正在考虑使用 ps 来获取父母的 pid,但我需要循环这个来获取曾祖父母的 pid。那是我需要的。谢谢。 – 拉姆克罗


对不起,有很多用户,每个人最多可以打开三个终端。整个脚本用于查找正在使用文件的终端。我使用 fuser 来查找使用文件的进程。然后使用 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

【讨论】:

    【解决方案5】:

    您是否考虑过使用“who -u”来告诉您哪个进程是给定 tty 的登录 shell,而不是使用 ptree?这将简化您的搜索 - 无论您还应该进行哪些其他更改。

    【讨论】:

    • 谢谢,但是终端进程太多,我需要使用文件查找。
    【解决方案6】:

    我只是根据您的脚本在这里做了一些琐碎的计时(调用“cat ptree.txt”而不是 ptree 本身)并证实了我的想法,即您所有的时间都花在了创建新的子进程和运行 ptree 本身上。除非您可以排除调用 ptree 的需要(也许有一种方法可以打开连接一次并重复使用它,例如使用 nslookup),否则您不会看到任何真正的收益。

    【讨论】:

      猜你喜欢
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      • 2017-08-18
      • 1970-01-01
      • 2019-11-02
      • 2016-07-04
      • 2012-05-12
      • 2010-12-01
      相关资源
      最近更新 更多