我想捕获(ssh->; capture)之后主机上显示的标准错误。
例如,当我尝试:
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($host);
my $out=$ssh->capture("cd /home/geek");
$ssh->error and
die "remote cd command failed: " . $ssh->error;
out put是:
child exited with code 1 at ./change_dir.pl line 32
我无法看到错误是什么。我在终端上没有这样的文件或目录。我想捕获相同的"没有这样的文件或导演"在$ out。
示例2,
my ($stdout,$stderr)=$ssh->capture("cd /home/geek");
if($stderr)
print"Error = $stderr";
else
print "$stdout"
我看到"错误="打印但没有在屏幕上看到$ stderr。 我看到$ stdout成功打印但是打印$ stderr不会仅打印"错误="得到印刷。
答案 0 :(得分:3)
当发生错误时,很可能不将出现在STDOUT
中,如果它出现在STDERR
中,则表示您没有发现错误。您需要以下列方式访问应用程序的退出代码。 (考虑到我现在只看到的问题的更新:请参阅结尾以了解如何获得STDERR。)
在capture
方法之后,您要检查$?
是否有错误(请参阅Net-OpenSSH)。解压缩以获取$ssh
实际运行的退出代码,然后查看该应用程序的文档以查看该代码的含义
$exit_code = $?;
if ($exit_code) {
$app_exit = $exit_code >> 8;
warn "Error, bit-shift \$? --> $app_exit";
}
要调查的代码是$app_exit
。
一个例子。我在项目中使用zip
,偶尔会发现3072
的错误(即$?
)。如果按照上面的方式解压缩,我会得到12
,这是zip
的实际退出。我查找了它的文档并很好地列出了退出代码,12
表示无需更新。这是zip
的设计决策,如果在归档中没有要更新的文件,则退出12
。然后该出口被打包成一个两字节的数字(在高位字节中),然后返回 ,这就是我在$?
得到的。
一般的失败模式,来自Perl docs中的system
if ($? == -1) { warn "Failed to execute -- " }
elsif ($? & 127) {
$msg = sprintf("\tChild died with signal %d, %s coredump -- ",
($? & 127), ($? & 128) ? 'with' : 'without');
warn $msg;
} else {
$msg = sprintf("\tChild exited with value %d -- ", $? >> 8);
warn $msg;
}
实际退出代码$? >> 8
由任何运行提供,因此其解释取决于该应用程序。您需要查看其文档,并希望其退出代码已记录在案。
请注意$ssh->error
似乎是为此任务而设计的。来自模块的文档
my $output = $ssh->capture({ timeout => 10 }, "echo hello; sleep 20; echo bye");
$ssh->error and warn "operation didn't complete successfully: ". $ssh->error;
印刷错误需要进一步调查。文档不会说出它是什么,但我希望上面讨论的解压缩代码(问题更新表明这个)。这里$ssh
只运行一个命令,它不知道出了什么问题。它只是取回命令的退出代码,待查看。
或者,您可以修改命令以获取STDERR
上的STDOUT
,请参阅下文。
capture
方法相当于Perl的反引号(qx
)。有很多关于如何从反引号中获取STDERR
的内容,而Perl自己的常见问题解答已经很好地写了in perlfaq8
。这里的一个复杂因素是,这不是qx
,而是模块的方法,更重要的是,它在另一台机器上运行。但是,"输出重定向"方法仍然可以不加修改地工作。可以编写命令(由$ssh
运行),以便将STDERR
重定向到其STDOUT
。
$cmd_all_output = 'your_whole_command 2>&1';
$ssh->capture($cmd_all_output);
现在,您将收到在STDOUT
打印的终端上显示的错误("没有此类文件或目录"),因此它将在您的$stdout
中结束。请注意,必须使用sh
shell语法,如上所述。还有更多它,所以请查阅(但这应该工作原样)。大多数情况下,它与退出代码描述中的消息相同。
您的代码中的检查是好的,第一道防线:运行外部命令时,总是检查$?
,为此,运行命令不需要感动。