4

次のコード スニペットは、ptree を使用して、返された結果から3 番目の PID を取得することにより、ユーザーの端末の 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

これをコーディングするより良い方法があるかどうか知りたいです。これは、実行に最も時間がかかるスクリプトの部分です。

注: このコードは、他のスニペットと共にループ内にあり、数回実行されます。

4

6 に答える 6

5

主な問題は、このコードがループしていることだと思います。ptreeを実行して結果を複数回解析する必要はありません!ptreeを一度実行して、後で使用できるデータ構造に配置する方法を理解する必要があります。おそらく、ある種の単純なハッシュで十分でしょう。%terminalsハッシュを保持して、それを再利用し続けることができる場合もあります。

いくつかの落とし穴...

  • あなたの「次の」ステートメントは両方とも私には不要のようです...あなたはそれらを削除することができるはずです。

  • 交換

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

と:

    $terminals{$user} .= " $1";
  • ファイルハンドルとして使用しているベアワードPTREEを$ptreeFなどに置き換えます...ベアワードの使用は約10年前にファイルハンドルで不要になりました:)

  • $ PID変数がすべて大文字である理由はわかりません...その変数には特別なものがあるように見えますが、そうではないため、コードの読者を混乱させる可能性があります。

于 2008-12-26T12:42:16.923 に答える
4

ptree外部コマンド (この場合は )を繰り返し実行するオーバーヘッドを回避することで、最高のパフォーマンス向上が得られると思います。読み取り中のデータ構造への直接インターフェースを提供する CPAN モジュールを探しますptreeLinux::名前空間を確認してください。( setuidptreeかどうかはわかりません。複雑になる可能性があります。)

上記のアドバイスはさておき、投稿されたスニペットのみに基づくいくつかの追加のスタイルと堅牢性に関するメモ (より大きなコードがそれらを無効にする場合は許してください):

  • strict少なくとも を使用することから始めます。レキシカルファイルハンドルも良い考えです。

  • open()コマンドを実行できない場合、大文字と小文字を区別せずに無視しているように見えますptree。これは多くの理由で発生する可能性があり、そのうちのいくつかはあなたが無視したいとは思えないものです。たとえば…</p>

  • コマンドへのフル パスを使用してptreeいるのではなく、それがパス内にあり、パス内のパスが正しいものであると想定しています。

于 2008-12-26T13:58:06.413 に答える
3

psを使用して親のpidを取得することを考えていましたが、曽祖父母のpidを取得するにはこれをループする必要があります。それが私に必要なものです。ありがとう。– lamcro


申し訳ありませんが、多くのユーザーがいて、それぞれが最大3つの端末を開くことができます。スクリプト全体を使用して、ファイルを使用している端末を検索します。私は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
于 2008-12-26T17:30:36.670 に答える
3

システムには何人のユーザーがいますか?これを反転できますか?システム内のすべての-pksh-kshプロセスとそのEUIDを一覧表示し、そこからマップを作成します。これは、ps/ptreeの1回の実行のみである可能性があります。

于 2008-12-26T14:02:11.053 に答える
2

who -uを使用する代わりに、特定のttyのログインシェルがどのプロセスであるかを示すために''を使用することを検討しましたptreeか?これにより、他の変更に関係なく、検索が簡単になります。

于 2008-12-26T14:17:09.277 に答える
1

ここでは、スクリプト(ptree自体の代わりに「catptree.txt」を呼び出す)に基づいて簡単なタイミングを実行し、すべての時間が新しいサブプロセスの作成とptree自体の実行に費やされていることを確認しました。ptreeを呼び出す必要性を考慮に入れられない限り(nslookupのように、接続を一度開いて再利用する方法があるかもしれません)、実際の利益は見られません。

于 2008-12-26T14:08:24.707 に答える