【问题标题】:perl remote execution errorperl远程执行错误
【发布时间】:2012-04-05 16:25:07
【问题描述】:

在下面的代码中,我尝试使用 Perl 脚本将 git 存储库克隆到另一台机器。

如果我打印$output,我会收到所有登录消息,即/etc/motd/ 的内容,但不是实际的命令输出。

如何解决这个问题?我在执行 ssh 命令时是否做错了什么?

    sub myexec_remote    
    {
       my($cmd, $hostname, $filename) = @_;

       my $stdout = $stderr = $exit= "";
       my ($output) = `ssh $hostname $cmd 2>&1`;
       ## this is the command i.e, executed
       ##command is  ssh 111.22.11.32 "git clone --bare gt@l.com:/nfs/git/ /nfs/new123/"
       $exit = $?;
       if (defined $output)
       {
       open(MYOUTFILE, ">$filename");
       print MYOUTFILE "$output";
       close(MYOUTFILE);
       }

    }

我正在使用反引号,因为有时 ssh 是在没有密码的情况下完成的,而且我看到 NET:SSH 模块不支持它...

【问题讨论】:

  • 没有密码?有密码,还是没有密码(= 无密码)?

标签: linux perl ssh perl-module


【解决方案1】:

这是因为您在列表上下文中使用了backticks operator

my ($output) = `ssh $hostname $cmd 2>&1`;

在列表上下文中调用时,反引号将返回行列表。您只捕获第一行,并将其放入$output。其他行被忽略。来自perldoc perlop

在标量上下文中,它作为单行(可能是多行)返回 字符串,如果命令失败,则为 undef。在列表上下文中,返回一个 行列表(但是您已经使用 $/ 或 $INPUT_RECORD_SEPARATOR),如果命令失败,则为空列表。

解决办法:

1. my $output = `ssh $hostname $cmd 2>&1`;

在标量上下文中调用反引号将导致 $output 成为多行字符串。

2. my @output = `ssh $hostname $cmd 2>&1`;

您可以在数组上下文中很好地调用反引号,但稍后您必须将整个数组打印到 MYOUTPUTFILE

其他cmets:

这些不是解决方案的一部分。解决方案本身应该足以修复您的错误。但是,它们可以降低出现错误的风险,并增加您的 Perl 知识。

  1. 尝试使用三参数版本的 open,而不是使用全局的二参数,并在文件无法打开时捕获错误:

    open(my $handle, '>', $filename) or die "Unable to open file, $!";

  2. 很多人决定使用IPC::System::Simple而不是反引号,因为当出现问题时您可以获得更多信息并且可以避免使用shell。

  3. 另一个选项是IPC::Open3,它甚至可以让您轻松捕获 STDOUT、STDERR 和退出代码。不过使用起来有点困难。

【讨论】:

  • 回复:“但根据文档,如果命令运行,将始终定义 $output”。不,当没有错误时,文档只是说它“返回行列表”。它并没有说至少会有一行,所以原始代码的$output 可能是未定义的。当然,在标量上下文中,情况就不同了。
【解决方案2】:

使用Net::OpenSSH:

use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($host, user => $user, password => $password);
my $output = $ssh->capture($cmd);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    • 2020-11-12
    • 1970-01-01
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多