如何快速找到用户';Perl中的终端PID?
下面的代码片段用于查找用户终端的PID,方法是使用ptree并从返回的结果中获取第三个PID。所有终端PID都存储在一个散列中,用户的登录名作为密钥如何快速找到用户';Perl中的终端PID?,perl,terminal,pid,Perl,Terminal,Pid,下面的代码片段用于查找用户终端的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 =
## 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并解析结果!您需要找到一种方法来运行ptree一次,并将其放入数据结构中,以便以后使用。也许某种简单的散列就足够了。您甚至可以只保留您的%terminals哈希并继续重用它 一些吹毛求疵的话
- 你的两个“下一步”陈述似乎 对我来说没必要。。。你应该 可以直接移除它们
- 替换
$terminals{$user} = $terminals{$user} . " $1";
- 替换您需要的裸字树 正在用作的文件句柄 $ptreeF或类似的。。。使用 光说空话对我来说是不必要的 大约10年前的filehandles:)
- 我不知道为什么你的$PID变量 都是大写。。。这可能会让人困惑 给代码的读者,因为它 看来有什么事 关于该变量的特殊性,以及 没有
ptree
,在本例中)的开销,您将获得最佳性能改进。我想寻找一个CPAN模块,它为ptree
正在读取的数据结构提供直接接口。检查名称空间,也许?(我不确定ptree
是否正确;这可能会使事情复杂化。)
除了上面的建议之外,还有一些仅基于发布的代码片段的附加样式和健壮性说明(如果较大的代码使它们无效,请原谅我):
- 至少,我会先使用
严格的
。这也是个好主意
- 当您无法
使用open()
命令时,您似乎在默默地忽略该情况。这种情况可能发生的原因有很多,我无法想象你会忽视其中的一些原因,比如ptree
- 您没有使用
命令的完整路径,而是假设它在您的路径中,并且您路径中的路径是正确的ptree
who-u
”来告诉您哪个进程是给定tty的登录shell,而不是使用ptree
?这将简化您的搜索-无论您还应该做哪些其他更改。我正在考虑使用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";
}
}
“这是脚本运行时间最长的部分。”其中哪一部分需要时间?ptree的执行,还是结果的混乱?这将有助于避免优化实际上没有任何区别的东西。ptree会减慢程序的速度。毫无疑问。我只是想知道是否有更好的方法来捕获ptree结果中第三行中的进程ID。这就是我从这段代码中所需要的。捕捉PID的方式看起来很合理。唯一的(微观)优化是您知道regexp将不匹配前两行。您可以只数三行,然后只在第三行进行regexp匹配。然而,考虑到时间是在ptree中,这有什么意义呢?请参阅我的另一个答案。AFAICT,ptree在循环中每次都使用不同的参数调用。Correct。ptree被称为循环中的各种时间。谢谢你的挑剔。我已经10多年没有使用perl了,因此此后的任何更改对我来说都是陌生的。我又成了一个傻瓜了。。。事实上,第二个“下一个”可能是必要的,因为它可能是从一个你没有展示的外部循环中逃逸出来的。对不起,有很多用户,每个用户最多可以打开三个终端。整个脚本用于查找正在使用文件的终端。我使用fuser查找使用文件的进程。然后使用ptree查找终端的pid。我打赌一个ps获取所有进程的数据会快得多,而且我看不出用户数量有任何实际问题。谢谢,但是终端进程太多了,我需要使用文件查找。我想用ps获取父进程的pid,但我需要循环这个来获取曾祖父的pid。这就是我需要的。谢谢
$terminals{$user} .= " $1";
#!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