在执行openssh到变量perl时无法捕获stderr

时间:2016-02-24 05:09:45

标签: perl stderr openssh

我想捕获(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不会仅打印"错误="得到印刷。

1 个答案:

答案 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语法,如上所述。还有更多它,所以请查阅(但这应该工作原样)。大多数情况下,它与退出代码描述中的消息相同。

您的代码中的检查是好的,第一道防线:运行外部命令时,总是检查$?,为此,运行命令不需要感动。