运行以下代码时,不打印最后一个服务器 - 脚本在第二个数组元素后面“挂起”。
my %readers;
my $command = "pgrep -f weblogic.Name";
foreach my $server(@servers) {
pipe($readers{$server},WRITER);
unless(my $pid = fork()) {
my $response = qx(ssh -q oracle\@$server "$command");
print WRITER $response;
exit();
}
}
foreach my $server (@servers) {
my $fh = $readers{$server};
my @procs = <$fh>;
chomp(@procs);
for my $proc (@procs) {
printf "%s\t%s\n", substr($server,8), $proc;
}
}
print "end\n";
输出如下:
$ ./get_stuck.pl
92 18196
93 27420
94 17635
95 10258
96 10831
'96'之后应该有一个服务器'97'输出,但是没有,并且脚本只是挂起/停止。
如果我更改阅读器部分以使用字符串而不是数组,如下所示:
foreach my $server (@servers) {
my $fh = $readers{$server};
my $procs = <$fh>;
printf "%s\n", $server;
}
...然后脚本打印所有服务器,包括'97',但是,如果命令有多个结果,这将只打印第一个结果(似乎在换行符中断)。换句话说,如果命令为给定服务器返回3个进程ID,则只打印第一个进程ID。
有关使用数组的原因的任何建议会导致脚本挂在最后一个元素上吗?或者也许(不太理想)我如何使用字符串,但检索所有结果?
答案 0 :(得分:2)
我还没有尝试过,但是:
此代码看起来像你自己陷入僵局。
<
>
会覆盖整个文件,即它会一直读到文件结尾(EOF)。WRITER
(子级会在退出时隐式关闭它)。这只发生在最后一个数组元素的原因是因为你正在使用一个裸字文件句柄(WRITER
),它实际上是一个全局变量。重新打开相同的句柄会先隐式关闭它;即,循环的第(n + 1)次迭代关闭第n个管道。只剩下最后一个WRITER
。
如果我是对的,那么修复就是:
foreach my $server(@servers) {
pipe($readers{$server},WRITER);
unless(my $pid = fork()) {
my $response = qx(ssh -q oracle\@$server "$command");
print WRITER $response;
exit();
}
close WRITER; # always close WRITER in the parent
}
但我还建议将代码更改为:
foreach my $server (@servers) {
pipe($readers{$server}, my $WRITER);
defined(my $pid = fork()) or die "$0: fork: $!\n";
unless($pid) {
my $response = qx(ssh -q oracle\@$server "$command");
print $WRITER $response;
exit();
}
close $WRITER;
}
即。检查fork
是否有错误并使用词法变量而不是裸字文件句柄。在这种情况下,close
实际上是可选的,因为$WRITER
在其范围的末尾(当前循环迭代)被隐式关闭,因为没有其他引用。
您可以使用管道打开来简化它:
foreach my $server (@servers) {
open $readers{$server}, '-|', 'ssh', '-q', "oracle\@$server", $command
or die "$0: ssh: $!\n";
}
最后,
my $fh = $readers{$server};
my @procs = <$fh>;
可以缩减为
my @proces = readline $readers{$server};
(我不喜欢<
>
运算符。在我看来,始终明确地写readline
或glob
会使其更具可读性。)