您的程序有一些危险信号。我在下面讨论它们,最后提出一种更好的编写代码的方法。
红旗 1
您问题中的代码尝试使用反引号执行外部命令并假设成功。您应该始终检查对操作系统的任何调用的状态。失败的`$command`
——也称为qx//
or ——readpipe
根据命令是否执行并失败或尝试执行命令是否失败,以一种或多种方式使自己知道:
- 特殊变量的值
$?
非零。
- 在执行失败的情况下
- 特殊变量
$!
包含失败的描述。
- 运算符返回标量上下文中的未定义值或列表上下文中的空列表。
使用 Perl,`$command`
为了执行 执行子shell $command
,因此子shell 可能是执行并失败的程序,例如,错误的命令语法。
下面示例中的一个命令在我的机器上成功。
#! /usr/bin/env perl
use strict;
use warnings;
my @commands = (
"bad syntax (",
"does-not-exist",
"/etc/passwd",
"perl --no-such-option",
"perl -le 'print q(Hello world)'",
);
foreach my $c (@commands) {
print "Capturing output of command $c...\n";
my $output = `$c`;
if ($? == 0) {
print " - command executed successfully!\n";
}
elsif ($? == -1) {
print " - command failed to execute: \$!=$!\n";
}
else {
print " - command exited with status " . ($? >> 8) . "\n";
}
print " - value of \$output is ",
(defined $output ? "" : "un"), "defined\n\n";
}
输出:
捕获命令错误语法的输出(...
sh:语法错误:“(”意外
- 命令以状态 2 退出
- 定义了 $output 的值
捕获命令的输出不存在...
无法执行“不存在”:./runcmds 第 16 行没有这样的文件或目录。
- 命令执行失败:$!=没有这样的文件或目录
- $output 的值未定义
正在捕获命令 /etc/passwd 的输出...
无法执行“/etc/passwd”:./runcmds 第 16 行的权限被拒绝。
- 命令执行失败:$!=Permission denied
- $output 的值未定义
正在捕获命令 perl --no-such-option... 的输出
无法识别的开关:--no-such-option(-h 将显示有效选项)。
- 命令以状态 29 退出
- 定义了 $output 的值
捕获命令 perl -le 'print q(Hello world)' 的输出...
- 命令执行成功!
- 定义了 $output 的值
红旗 2
注意例如输出行
无法执行“不存在”:./runcmds 第 16 行没有这样的文件或目录。
我没有编写生成此警告的代码。相反,它是自动发生的,因为我使用该行启用了警告编译指示use warnings
。如果你启用了警告,Perl 至少会提示你问题的原因,所以我假设你没有启用警告。
这是另一个危险信号。警告可以帮助您。始终为任何重要的程序启用它们。
红旗 3
最后,您$1
无条件地使用正则表达式捕获变量,当匹配失败并且您从不同的匹配中获取捕获的值时,这种习惯会导致令人惊讶的错误。您应该始终将 , 和 Friends 的用法包含$1
在$2
条件中,例如,
if (/pa(tte)rn/) {
do_something_with $1;
}
推荐的修复
在 shebang 行之后的代码顶部附近,您应该立即添加该行
use warnings;
我也会推荐
use strict;
但这可能需要更多的工作来清理您的代码。我们在这里帮助您理解和克服您在这项有价值的努力中发现的任何问题。
使用output_of
下面来捕获命令的输出或通过适当的诊断而死。
sub output_of {
my($cmd) = @_;
my $output = `$cmd`;
return $output if $? == 0;
if ($? == -1) {
die "$0: $cmd failed to execute: $!\n";
}
elsif ($? & 127) {
my $signal = $? & 127;
my $core = ($? & 128) ? ", core dumped" : "";
die "$0: $cmd died with signal $signal$core\n";
}
else {
die "$0: $cmd exited with status " . ($? >> 8) . "\n";
}
}
您问题中的代码部分变为
my $output;
$output = output_of 'ec2-run-instances ami-8e1fece7 -k mykey -t t1.micro';
if ($output =~ /INSTANCE\s+(i-\w+)\s/) {
my $instance_id = $1;
$output = output_of "ec2-describe-instances $instance_id";
if ($output =~ /(ec2-(\d+-\d+-\d+-\d+).\S+)/) {
print "$0: found instance $2\n"; # or whatever
}
else {
die "$0: no ec2-IP in ec2-describe-instances output:\n$output";
}
}
else {
die "$0: no INSTANCE in ec2-run-instances output:\n$output";
}
通过这些更改,您的代码将为处理输出的所有故障模式提供标准错误诊断,ec2-run-instances
而ec2-describe-instances
不是让您想知道出了什么问题。