tl;dr; 如何从脚本中捕获 stderr 以获得更具体的错误,而不仅仅是依赖来自 Net::OpenSSH 的一般错误?
我有一个棘手的问题,我正在尝试解决。Net::OpenSSH 仅适用于协议版本 2。 但是,我们有许多网络设备仅支持版本1。 我正在尝试找到一种优雅的方法来检测远程端是否是错误的版本。
连接到版本 1 设备时,标准服务器上会显示以下消息
协议主要版本不同:2 与 1
但是,Net::OpenSSH返回的错误如下
无法建立主SSH连接:密码错误或主进程意外退出
这个特定的错误太笼统了,不能只解决协议版本差异。 我需要通过切换到另一个库来处理协议差异,我不想为每个连接错误都这样做。
我们使用了一个相当复杂的过程,该过程最初是为仅 telnet 访问而连接的。我们加载一个"comm"对象,然后确定路由器类型等内容。 该通信对象调用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。
任何想法将不胜感激。
捕获主 stderr 流并在之后进行检查。
请参阅此处如何操作。
您可以使用的另一种方法是打开远程 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 的工作方式都不同,特别是对于网络设备 shell 非常自动化不友好。
无论如何,CPAN 上有几个模块试图做到这一点,为每种 shell(或操作系统)实现一个处理程序。例如,检查Oliver Gorwits的模块Net::CLI::Interact,Net::Appliance::session和Net::Appliance::P hrasebook。短语手册方法似乎非常合适。