3

すべてコンパイル/パッケージ化し<name-of-the-app>.jarてサーバー上で実行する小さなJavaアプリのスイートがあります。時折、そのうちの 1 つが例外をスローし、窒息して死ぬことがあります。これらの実行可能な JAR がすべてまだ実行されているかどうかを定期的にポーリングし、実行されていないものがある場合は、電子メールを送ってどれが死んでいるかを通知する、簡単で汚い Perl スクリプトを作成しようとしています。

これを手動で判断するには、ps -aef | grep <name-of-app>確認するアプリごとに を実行する必要があります。たとえば、myapp.jarがプロセスとして実行されているかどうかを確認するには、 を実行しps -aef | grep myapp、 を表す JVM プロセスを説明する grep の結果を探しますmyapp.jar。この手動チェックは今や退屈になりつつあり、自動化の最有力候補です!

プロセスが実行されているかどうかを確認するコードを実装しようとしています。これを、実行可能 JAR の名前を受け入れてorsubを返すa にしたいと思います。truefalse

sub isAppStillRunning($appName) {
    # Somehow run "ps -aef | grep $appName"

    # Somehow count the number of processes returned by the grep

    # Since grep always returns itself, determine if (count - 1) == 1.
    # If so, return true, otherwise, false.
}

subアプリの名前を渡し、通常のコマンドを実行し、 によって返される結果の数をカウントできる必要がありgrepます。a を実行するとgrep常に少なくとも 1 つの結果 (grepコマンド自体) が返されるため、(結果の数 - 1) が 1 に等しい場合にアプリが実行中であることを示すロジックが必要です。

私は Perl を初めて使用するので、このロジックを実装する方法を理解するのに苦労しています。これまでの私の最善の試みは次のとおりです。

sub isAppStillRunning($appName) {
    # Somehow run "ps -aef | grep $appName"
    @grepResults = `ps -aef | grep $appName`;

    # Somehow count the number of processes returned by the grep
    $grepResultCount = length(@grepResults);

    # Since grep always returns itself, determine if (count - 1) == 1.
    # If so, return true, otherwise, false.
    if(($grepResultCount - 1) == 1)
        true
    else
        false
}

次に、同じ Perl スクリプト内からメソッドを呼び出すには、次のように実行します。

&isAppStillRunning("myapp");

サブを定義し、適切なアプリ名でそれを呼び出すためのヘルプは大歓迎です。前もって感謝します!

4

3 に答える 3

4

CPAN のProc::ProcessTableモジュールを使用すると、約 10 億倍簡単になります。以下に例を示します。

use strict;
use warnings;
use Proc::ProcessTable;

...
sub isAppStillRunning { 
    my $appname = shift;
    my $pt = Proc::ProcessTable->new;
    my @procs = grep { $_->fname =~ /$appname/ } @{ $pt->table };

    if ( @procs ) { 
        # we've got at least one proc matching $appname. Hooray!
    } else { 
        # everybody panic!
    }
}

isAppStillRUnning( "myapp" );

心に留めておくべきいくつかの注意事項:

  • とをオンにstrictwarningsます。彼らはあなたの友達です。
  • プロトタイプでサブルーチン引数を指定しません。(Perl のプロトタイプはまったく異なることを行いますが、これは望ましくありません。)配列shiftから引数を取得するために使用します。@_
  • &サブルーチンの呼び出しには使用しないでください。その名前を使用してください。
  • スカラー コンテキストで評価された配列 ( 内にあるかどうかを含むif) は、そのサイズを示します。length配列では機能しません。
于 2012-09-26T00:37:46.040 に答える
3

あなたのサブルーチンはほとんどそこにありますが、最後の if-else 構造を修正する必要があり、場合によっては、Perl のイディオムが作業を楽にしてくれます。

Perlにはプロトタイプがありますが、それらは最悪です

sub isAppStillRunning($appName) {

動作しないでしょう。代わりに使用

sub isAppStillRunning {
  my ($appName) = @_;

@_配列は、関数への引数を保持します。Perl にはいくつかの単純なプロトタイプ (sub name(&$@) {...}構文) がありますが、壊れており、高度なトピックであるため、使用しないでください。

Perlにはgrepが組み込まれています

`ps -aef | grep $appName`;

これは、複数の行を含む可能性がある 1 つの文字列を返します。出力を改行で分割し、手動で grep することができます。これは、変数を補間するよりも安全です。

my @lines   = split /\n/ `ps -aef`;
my @grepped = grep /$appName/, @lines;

この関数を使用して、次openへのパイプを明示的に開くこともできpsます。

my @grepped = ();
open my $ps, '-|', 'ps -aef' or die "can't invocate ps";
while (<$ps>) {
  push @grepped if /$appName/;
}

これはまったく同じですが、より優れたスタイルです。出力からすべての行を読み取り、 yourを含むすべての行を配列psにプッシュします。$appName@grepped

スカラー vs. リスト コンテキスト

Perlには、「コンテキスト」と呼ばれるこの珍しいものがあります。リストコンテキストスカラーコンテキストがあります。たとえば、サブルーチン呼び出しは引数リストを取ります - したがって、これらのリストは (通常) リスト コンテキストを持ちます。対照的に、2 つの文字列の連結はスカラー コンテキストです。

配列は、コンテキストに応じて異なる動作をします。リスト コンテキストでは、要素に評価されますが、スカラー コンテキストでは、要素の数に評価されます。そのため、要素を手動でカウントする (またはlength文字列に対して機能する関数を使用する) 必要はありません。

したがって、次のようになります。

 my @array = (1, 2, 3);
 print "Length: ", scalar(@array), "\n"; # prints "Length: 3\n"
 print "Elems: ", @array, "\n";          # prints "Elems: 123\n";
 print "LastIdx: ", $#array, "\n";       # prints "LastIdx: 2\n";

最後の形式 は$#array、配列内の最後のインデックスです。特別な変数をいじらない限り、これは と同じ@array - 1です。

関数はscalarスカラー コンテキストを強制します。

Perlにはブール値がありません

truePerl には boolean データ型がないため、 orfalseキーワードはありません。代わりに、特に明記されていない限り、すべての値が true です。偽の値は次のとおりです。

空の文字列""、数字のゼロ0、文字列のゼロ"0"、特別な値undef、および遭遇しないその他の奇妙さ。

したがって、通常は1true および0false として使用します。

if/else コンストラクトには中括弧が必要です

つまり、おそらく次のことを意味していました。

if (TEST) {
  return 1;
} else {
  return 0;
}

これは と同じreturn TESTで、TEST は条件です。

究極の削減

これらのトリックを使用すると、サブは次のように短く書くことができます

sub isAppStillRunning {
   return scalar grep /$_[0]/, (split /\n/, `ps -aef`);
}

これは、アプリ名を含む行数を返します。

于 2012-09-26T00:43:35.327 に答える
1

次のようにルーチンを変更できます。

sub isAppRunning {
    my $appName = shift;
    @grepResults = `ps -aef | grep $appName`;
    my $items = 0;
    for $item(@grepResults){
        $items++;
    }
    return $items;
}

これは @grepResults を反復処理し、必要に応じて $item を検査できるようにします。

このように呼び出すと、プロセスの数が返されます。

print(isAppRunning('myapp') . "\n"); 
于 2012-09-26T00:39:45.797 に答える