tl; dr; 如何从脚本中捕获stderr以获取更具体的错误,而不仅仅是依赖Net :: OpenSSH中的一般错误?
我有一个棘手的问题,我正试图解决。 Net :: OpenSSH仅适用于协议版本2.但是我们有许多网络设备只支持版本1.我试图找到一种优雅的方法来检测远程端是否是错误的版本。
连接到版本1设备时,stderr上会显示以下消息
协议主要版本不同:2对1
然而,Net :: OpenSSH返回的错误如下
无法建立主SSH连接:错误密码或主进程意外退出
此特定错误过于笼统,并不仅仅解决协议版本差异。我需要通过切换到另一个库来处理协议差异,我不想为每个连接错误执行此操作。
我们使用一个相当复杂的过程,该过程最初仅用于访问telnet。我们加载一个“comm”对象,然后确定类似路由器类型等东西.com通信对象调用Net :: OpenSSH传递命令。
示例:
my $sshHandle = eval { $commsObject->go($router) };
my $sshError = $sshHandle->{ssh}->error;
if ($sshError) {
$sshHandle->{connect_error} = $sshError;
return $sshHandle;
}
stderr上出现协议错误的地方在这里
$args->{ssh} = eval {
Net::OpenSSH->new(
$args->{node_name},
user => $args->{user},
password => $args->{tacacs},
timeout => $timeout,
master_opts => [ -o => "StrictHostKeyChecking=no" ]
);
};
我想要做的是传递stderr协议错误而不是Net :: OpenSSH传回的一般错误。我想在脚本中执行此操作,但我不确定如何从脚本中捕获stderr。
任何想法都会受到赞赏。
答案 0 :(得分:2)
捕获主stderr流并在之后检查它。
请参阅here如何操作。
您可以使用的另一种方法是打开远程SSH服务器的套接字。它发回的第一件事是它的版本字符串。例如:
$ nc localhost 22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-8
^C
根据该信息,您应该能够推断服务器是否支持SSH v2。
最后,如果您还需要与SSH v1服务器通信,我的其他模块Net::SSH::Any的开发版本可以使用操作系统本机SSH客户端来完成,尽管它为每个命令建立了新的SSH连接
use Net::SSH::Any;
my $ssh = Net::SSH::Any->new($args->{node_name},
user => $args->{user},
password => $args->{tacacs},
timeout => $timeout,
backends => 'SSH_Cmd',
strict_host_key_checking => 0);
更新:回应以下关于在同一会话中发送多个命令的问题的Bill评论:
通过同一会话发送命令的问题是你必须与远程shell通信,并且没有办法以通用的方式可靠地做到这一点,因为每个shell都以不同的方式做事,特别是对于网络设备那些非常自动化的炮弹。
无论如何,CPAN上有几个模块试图这样做,为每种shell(或OS)实现一个处理程序。例如,查看Oliver Gorwits的模块Net::CLI::Interact,Net::Appliance::Session和Net::Appliance::Phrasebook。短语手册似乎非常合适。