Я сделал собственную подпрограмму для запуска различных команд терминала в Perl с использованием Open3.
Я столкнулся со странной проблемой с snmpwalk, когда я запускаю команду в терминале, она работает, а с Open3 - нет.
Саб это:
sub run_cmd {
my ( $cmd, @args ) = @_;
my ( $infh, $outfh, $errfh, $pid, $out, $err );
use Symbol 'gensym';
$errfh = gensym(); # open3 does not init stderr, we have to do it.
output( "run_cmd: $cmd @args\n", 2, 1 ); #for debug
eval { $pid = open3( $infh, $outfh, $errfh, $cmd, @args ); } or do {
if ($@) {
output("Error: open3 error $@\n");
exit $CODES{CRITICAL}; #exit 2;
}
};
{ # anonym block to limit $/ redefinition
local $/ = undef;
$out = <$outfh>;
$err = <$errfh>;
}
return ( $out, $err );
}
Я называю это с помощью:
($res, $err) = run_cmd("snmpwalk", "-c public -v1", "somehostname", "NETAPP-MIB::aggrName");
Если я хочу запустить следующую команду:
snmpwalk -c public -v1 somehostname NETAPP-MIB::aggrName
Он возвращается как $err:
snmpwalk: имя безопасности не указано
Если я запускаю ту же самую команду в терминале, она возвращает мои результаты:
NETAPP-MIB::aggrName.1 = STRING: SAS2
NETAPP-MIB::aggrName.2 = СТРОКА: SATA1
...
Я обнаружил, что NET::SNMP может решить мою проблему, но я не могу установить его из-за защищённой ОС Linux без возможности установки.
Я действительно не понимаю, почему это не работает.
перл -v: 5.8.8
Спасибо!
$out = <$outfh>; $err = <$errfh>;
вызовет взаимоблокировку, если дочерний элемент достаточно выведет в STDERR. Я рекомендую использовать IPC::Run3 или IPC::Run вместо все еще очень низкоуровневого IPC::Open3. Если вы хотите придерживаться IPC::Open3, вам придется использовать IO::Select, потоки или какую-либо форму асинхронного ввода-вывода, чтобы избежать возможности взаимоблокировки. - person ikegami   schedule 08.05.2014