在下面的代码中,我尝试使用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模块不支持它...
答案 0 :(得分:2)
这是因为您在列表上下文中使用backticks operator :
my ($output) = `ssh $hostname $cmd 2>&1`;
在列表上下文中调用时,反引号将返回一个行列表。您只捕获第一行,并将其放在$output
中。其他行被忽略。来自perldoc perlop
:
在标量上下文中,它作为单个(可能是多行)返回 字符串,如果命令失败,则为undef。在列表上下文中,返回a 行列表(但是你用$ /或定义了行 $ INPUT_RECORD_SEPARATOR),如果命令失败,则为空列表。
1. my $output = `ssh $hostname $cmd 2>&1`;
在标量上下文中调用反引号将导致$ output为多行字符串。
2. my @output = `ssh $hostname $cmd 2>&1`;
您可以在数组上下文中调用反引号,但是您必须稍后将整个数组打印到MYOUTPUTFILE
这些不是解决方案的一部分。解决方案本身应足以修复您的错误。但是,它们可以降低错误风险,并提高您的Perl知识。
尝试使用open的三参数版本,而不是使用全局的两参数,并在无法打开文件时捕获错误:
open(my $handle, '>', $filename) or die "Unable to open file, $!";
很多人决定使用IPC::System::Simple而不是反引号,因为当出现问题时您可以获得更多信息并且可以避免使用shell。
另一个选项是IPC::Open3,它甚至可以让您轻松捕获STDOUT,STDERR和exitcode。但是使用起来有点困难。
答案 1 :(得分:0)
使用Net::OpenSSH:
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($host, user => $user, password => $password);
my $output = $ssh->capture($cmd);