3

我有一套小型 Java 应用程序,它们都编译/打包到<name-of-the-app>.jar我的服务器上并在我的服务器上运行。偶尔其中一个会抛出异常,窒息而死。我正在尝试编写一个 quick-n-dirty Perl 脚本,该脚本将定期轮询以查看所有这些可执行 JAR 是否仍在运行,如果其中任何一个不在运行,请给我发送电子邮件并通知我哪个已死。

要手动确定这一点,我必须为ps -aef | grep <name-of-app>要检查的每个应用程序运行一个。例如,要查看是否myapp.jar作为进程运行,我运行ps -aef | grep myapp并查找描述代表 的 JVM 进程的 grep 结果myapp.jar。这种手动检查现在变得乏味,是自动化的主要候选者!

我正在尝试实现检查进程是否正在运行的代码。我想让sub它接受可执行 JAR 的名称并返回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. 由于运行 agrep始终会产生至少一个结果(grep命令本身),因此我需要说明如果 (# of results - 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");

非常感谢任何有关定义 sub 然后使用正确的应用程序名称调用它的帮助。提前致谢!

4

3 回答 3

4

使用CPAN的Proc::ProcessTable模块会容易十亿倍。这是它可能看起来的示例:

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

您的 sub 几乎就在那里,但最终的 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/;
}

这是完全平等的,但更好的风格。它从ps输出中读取所有行,然后将所有行与您一起推$appName送到@grepped数组中。

标量与列表上下文

Perl 有一个不寻常的东西叫做“上下文”。有列表上下文标量上下文。例如,子例程调用采用参数列表 - 因此这些列表(通常)具有列表上下文。相反,连接两个字符串是一个标量上下文。

Arrays behave differently depending on their context. In list context, they evaluate to their elements, but in scalar context, they evaluate to the number of their elements. So there is no need to manually count elements (or use the length function that works on strings).

So we have:

 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";

The last form, $#array, is the last index in the array. Unless you meddle with special variables, this is the same as @array - 1.

The scalar function forces scalar context.

Perl Has No Booleans

Perl has no boolean data type, and therefore no true or false keywords. Instead, all values are true, unless stated otherwise. False values are:

空字符串""、数字 zero 0、字符串 zero "0"、特殊值undef以及其他一些您不会遇到的怪事。

所以一般用1as true 和0as false。

if/else 结构需要花括号

所以你可能的意思是:

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

这与 相同return TEST,其中 TEST 是一个条件。

终极还原

使用这些技巧,你的 sub 可以写成

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 回答