我试图找出监视shell脚本中进程ID列表的最佳方法。我不想全部监控它们,只是一个自定义列表。
例如: 如果我有进程名称::
Orange-TE--02
Orange-TE--03
Apple-JI--01
Orange-TE--09
Orange-JI--06
我正在尝试编写一个只监视Orange-TE-02,Apple-JI-01,Orange-JI-06的脚本,因此如果其中任何一个出现故障,将发送一个电子邮件警报哪个过程失败了。如果Orange-TE-03,Orange-TE-09熄火,没有任何反应。
这是流程的输出' process.sh -s
name Process Pid
---------------- ------------------------------- ----
tneal01 Orange-JI--06 3443
tneal01 Orange-TE--09 2233
tneal01 Orange-JI--01 5533
tneal01 Apple-TE--03 9384
tneal01 Orange-TE--02 4992
我正在考虑将结果输出到文件并列出预期的进程名称列表,那些不匹配的列表发送电子邮件说
Alert Process:
Apple-TE--03
Orange-TE--02
Are down
不确定如何做到这一点。任何帮助将不胜感激。
谢谢!
答案 0 :(得分:2)
更新添加了电子邮件和评论的代码 更新添加了后续问题的答案
使用Perl脚本
use warnings 'all';
use strict;
my @watch = qw(Orange-TE--02 Apple-JI--01 Orange-JI--06);
# Extract second column from the table of running processes, drop header line
my @running = map { (split)[1] } `process.sh -s`;
shift @running;
my @down;
foreach my $proc_name (@watch) {
push @down, $proc_name if not grep { /^$proc_name$/ } @running;
}
print "$_ is down\n" for @down;
send_email(@down) if @down;
sub send_email {
my @data = @_;
# Write a file (but use File::Temp) and attach for a multi-line message
my $down_file = "services_down.$$";
open my $fh, '>', $down_file or die "Can't open $down_file: $!";
print $fh "$_\n" for @data;
close $fh;
my $cmd = "echo \"Services down: @data. See attached.\" | " .
"mailx -a $down_file -s \"Services down\" user\@email";
# Or, for an email with a single-line body
# my $cmd = "echo @data | mailx -s \"Services down\" user\@email";
system($cmd) == 0 or do {
warn "Error with system($cmd): $!";
warn "File $down_file left behind for debugging. Remove.";
return;
};
unlink $down_file or warn "Can't unlink $down_file $!";
return 1;
}
电子邮件说明。如果使用mailx
,我们无法将换行符输入其中。因此,如果电子邮件需要具有每行服务,我们可以写入文件并将文件附加到邮件中。该文件已删除,如果您希望保留它,请更改该文件。我用PID($$
)标记其名称,但注意这还不够 - 如果在进程中写入多个此类文件,则只保留最后一个。最好将核心File::Temp用于临时文件。或者使用注释掉的版本,整个身体都在一行中。然后没有理由写这个文件。只有在运行system
时出现问题,才会触发$cmd
上的错误检查。如果它运行正常但电子邮件本身失败(例如,地址错误),则无法检测到。所有这一切的替代方案是使用许多模块之一来发送电子邮件。
请注意,List::Util和List::MoreUtils有许多有用的例程,因此上述内容可以为if none { /.../ } @running;
。这里的改进是微妙的,但往往是非常直接的。
我不知道应该如何监控它,但你可以把它放在一个循环中,如
for (1..$max_time_steps) {
# code above
sleep 1;
}
或者你可以在while (1) { ... }
内部以适当的条件确定何时爆发。
这个问题的一个变种被问到了一个新的问题,这个问题被搁置(正如我完成输入代码并解释为什么我决定在那里回答)并且现在已经过去了。看到它的不同之处。以下是 问题的答案。差异显示在最后。
使用哈希来运行process.sh -s
返回的进程,其中每个进程名是一个键,其中包含最后一列的值(PID /“向下”)。 process.sh
的输出首先被送入数组,以便丢弃标题。
use warnings 'all';
use strict;
my @watch = qw(Orange-TE--02 Apple-TE--03 Orange-JI--01);
my @procs_info = `process.sh -s`;
my %running = map { (split)[1,2] } @procs_info[2..$#procs_info];
print "$_ => $running{$_}\n" for keys %running; # just to see it
my @down;
foreach my $proc_name (@watch)
{
push @down, $proc_name
if !exists $running{$proc_name}
or $running{$proc_name} eq 'Down';
}
if (@down) {
print "$_ is down\n" for @down;
# send email
}
我将@down
添加到受监视的进程中,如果它甚至不在运行的进程列表中。如果错了就改变。
对于记录,这里是另一个问题(以及我如何测试)的不同之处
my @procs_info = <DATA>; # The only change to the above code
# same code ...
__DATA__
name Process Pid
---------------- ------------------------------- ----
tneal01 Orange-JI--06 3443
tneal01 Orange-TE--09 Down
tneal01 Orange-JI--01 5533
tneal01 Apple-TE--03 Down
tneal01 Orange-TE--02 4992
答案 1 :(得分:0)
processes_to_be_tracked=('Apple-TE--03' 'Orange-TE--02')
running_processes=( $(process.sh -s | awk '{print $2}') )
non_running=()
for process_name in ${processes_to_be_tracked[@]}; do
if [[ "${running_processes[*]}" == *$process_name* ]]; then
echo "$process_name is running"
else
echo "$process_name is not running"
non_running+=($process_name)
fi
done
send-alert-mail-with-names-of-dead-processes "${non_running[*]}"