我有一套小型Java应用程序,它们都编译/打包到<name-of-the-app>.jar
并在我的服务器上运行。偶尔其中一个会抛出异常,窒息而死。我正在尝试编写一个快速脏的Perl脚本,它将定期轮询以查看是否所有这些可执行JAR仍在运行,如果它们中的任何一个都没有运行,请给我发一封电子邮件并通知我哪一个已经死了。< / p>
要手动确定,我必须为我要检查的每个应用运行ps -aef | grep <name-of-app>
。例如,要查看myapp.jar
是否作为进程运行,我运行ps -aef | grep myapp
,并查找描述代表myapp.jar
的JVM进程的grep结果。这种手动检查现在变得乏味,是自动化的主要候选者!
我正在尝试实现检查进程是否正在运行的代码。我想将其设为sub
,接受可执行JAR的名称并返回true
或false
:
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
返回的结果数。由于运行grep
总是会导致至少一个结果(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然后使用正确的应用程序名称调用它的帮助都非常感谢。提前谢谢!
答案 0 :(得分: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" );
要记住的一些注意事项:
strict
和warnings
。他们是你的朋友。shift
从@_
数组中获取参数。&
来调用子程序;只需使用它的名字。if
)是否为您提供了大小。 length
不适用于数组。 答案 1 :(得分:3)
你的潜艇几乎在那里,但最后的if-else结构必须得到纠正,在某些情况下,Perl成语可以让你的生活更轻松。
sub isAppStillRunning($appName) {
不起作用。而是使用
sub isAppStillRunning {
my ($appName) = @_;
@_
数组包含函数的参数。
Perl有一些简单的原型(sub name(&$@) {...}
语法),但它们已被破坏,并且是一个高级主题,所以不要使用它们。
`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有这种不寻常的东西叫做“上下文”。有列表上下文和标量上下文。例如,子例程调用采用参数列表 - 因此这些列表(通常)具有列表上下文。相比之下,连接两个字符串是一个标量上下文。
根据其上下文,数组的行为会有所不同。在列表上下文中,它们会评估其元素,但在标量上下文中,它们会评估其元素的数量。因此无需手动计算元素(或使用适用于字符串的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没有布尔数据类型,因此没有true
或false
个关键字。相反,除非另有说明,否则所有值均为真。错误的值是:
空字符串""
,数字零0
,字符串零"0"
,特殊值undef
以及其他一些您不会遇到的奇怪之处。
因此,通常将1
设为true,将0
设为false。
所以你可能意味着:
if (TEST) {
return 1;
} else {
return 0;
}
与return TEST
相同,其中TEST是条件。
使用这些技巧,你的潜艇可以写成
sub isAppStillRunning {
return scalar grep /$_[0]/, (split /\n/, `ps -aef`);
}
这将返回包含您的应用名称的行数。
答案 2 :(得分: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");