以下代码片段用于查找用户终端的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
我想知道是否有更好的方法对此进行编码。这是脚本中运行时间最长的部分。
注意:此代码以及其他代码段位于循环内并执行几次。
答案 0 :(得分:5)
我认为主要问题是此代码处于循环中。您不需要运行ptree并多次解析结果!您需要找到一种方法来运行ptree一次并将其放入一个稍后可以使用的数据结构中。可能是某种简单的哈希就足够了。您甚至可以只保留%终端哈希并继续重复使用它。
一些挑剔...
你的两个“下一个”陈述似乎都是 我没必要......你应该这样 能够删除它们。
替换
$terminals{$user} = $terminals{$user} . " $1";
使用:
$terminals{$user} .= " $1";
替换您的裸字PTREE 用作文件句柄 $ ptreeF或其他一些......使用 裸露变得不必要了 filehandles大约10年前:)
我不知道为什么你的$ PID变量 是全部大写......这可能令人困惑 对你的代码的读者,因为它 看起来有什么东西 特别关于那个变量,和 没有。
答案 1 :(得分:4)
我认为通过避免重复执行外部命令(在这种情况下为ptree
)的开销,您将获得最佳性能提升。我会寻找一个CPAN模块,它为ptree
正在读取的数据结构提供直接接口。可能检查Linux::命名空间? (我不确定ptree
是setuid;这可能会使事情复杂化。)
除了上述建议之外,还有一些额外的样式和健壮性注释仅基于发布的片段(如果较大的代码使它们无效,请原谅我):
我开始使用strict
,至少。 Lexical filehandles也是一个好主意。
当您无法open()
ptree
命令时,您似乎默默地忽略了这种情况。这可能有很多原因,其中一些我无法想象你想忽视,例如...
您没有使用ptree
命令的完整路径,而是假设它在您的路径中 - 并且路径中的那个是正确的。
答案 2 :(得分:3)
系统上有多少用户?你能倒这个吗?列出系统中的所有-pksh-ksh进程及其EUID,并从中构建映射 - 可能只执行一次ps / ptree。
答案 3 :(得分:3)
我正在考虑使用ps来获取父母的pid,但是我需要循环这个以获得曾祖父母的pid。这就是我需要的那个。谢谢。 - lamcro
抱歉,有很多用户,每个用户最多可以打开三个终端。整个脚本用于查找正在使用文件的终端。我使用fuser来查找使用文件的进程。然后使用ptree查找终端的pid。 - lamcro
如果您已经(或可以获得)使用文件的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
答案 4 :(得分:2)
您是否考虑使用“who -u
”告诉您哪个进程是给定tty的登录shell而不是ptree
?这样可以简化您的搜索 - 无论您还应该做出哪些其他更改。
答案 5 :(得分:1)
我刚刚根据你的脚本(称为“cat ptree.txt”而不是ptree本身)做了一些微不足道的计时,并确认了我的想法,你所有的时间都花在创建新的子流程和运行ptree本身上。除非你可以考虑不需要调用ptree(也许有一种方法可以打开连接并重用它,就像使用nslookup一样),你不会看到任何真正的收益。