You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Perl的Net::OpenSSH远程执行sudo命令遇错误,请求协助解决

解决Net::OpenSSH执行sudo命令报错及多命令执行问题

问题场景

以普通用户身份通过SSH连接远程主机,需执行以下环境配置及sudo权限命令:

export http_proxy=http://xxxx.xx.xx.com:8080
export https_proxy=http://xxxx-xxxx.xx.xx.com:8080
sudo /etc/init.d/filebeat restart
sudo tail -f /var/log/filebeat/filebeat

使用Perl的Net::OpenSSH模块执行Filebeat重启命令时,代码如下:

my $ssh = Net::OpenSSH->new("$username\@$Hostname", password => $pass);
my @cmdF = "/etc/init.d/filebeat restart";
print "Restarting filebeat for $webHosts[$i]";
my @cmdF = "/etc/init.d/filebeat restart";
my $outputF = $ssh->capture({stdin_data=>"$pass\n"}, 'sudo', '-Sk', '-p', '', '-', @cmdF);
print "\nCurrent Filebeat Status : $outputF\n\n";

执行后触发错误:

sudo: /etc/init.d/filebeat restart: command not found

错误原因及修复方案

1. 修复sudo命令参数传递错误

核心原因:@cmdF将整个命令作为单个元素传递,sudo会把/etc/init.d/filebeat restart当作完整命令名查找,导致找不到命令。需将命令拆分为独立参数:

修改命令定义:

my @cmdF = ('/etc/init.d/filebeat', 'restart');

调整执行代码(移除多余的-参数,该参数用于从标准输入读命令,直接传递参数更可靠):

my $outputF = $ssh->capture({stdin_data => "$pass\n"}, 'sudo', '-Sk', '-p', '', @cmdF);

2. 执行环境变量配置命令

远程主机设置http_proxy和https_proxy为普通用户权限操作,可直接通过capture方法执行:

# 设置http_proxy
$ssh->capture('export http_proxy=http://xxxx.xx.xx.com:8080');
# 设置https_proxy
$ssh->capture('export https_proxy=http://xxxx-xxxx.xx.xx.com:8080');

若需让后续sudo命令继承这些环境变量,有两种方式:

  • 远程主机修改sudoers配置,添加Defaults env_keep += "http_proxy https_proxy"
  • 在sudo命令中直接指定环境变量:
my $outputF = $ssh->capture({stdin_data => "$pass\n"}, 
                            'sudo', '-Sk', '-p', '', 
                            'http_proxy=http://xxxx.xx.xx.com:8080',
                            'https_proxy=http://xxxx-xxxx.xx.xx.com:8080',
                            @cmdF);

3. 处理sudo tail -f实时输出

tail -f是持续输出命令,capture方法会等待命令结束,无法获取实时流。需使用pipe_out方法处理:

my ($fh, $pid) = $ssh->pipe_out({stdin_data => "$pass\n"}, 
                                'sudo', '-Sk', '-p', '', 
                                'tail', '-f', '/var/log/filebeat/filebeat');

# 实时读取日志输出
while (my $line = <$fh>) {
    print "Filebeat Log: $line";
}

# 结束后清理资源
close $fh;
waitpid $pid, 0;

完整整合代码

my $ssh = Net::OpenSSH->new("$username\@$Hostname", password => $pass);
die "SSH连接失败: " . $ssh->error if $ssh->error;

# 配置环境变量
$ssh->capture('export http_proxy=http://xxxx.xx.xx.com:8080');
$ssh->capture('export https_proxy=http://xxxx-xxxx.xx.xx.com:8080');

# 重启Filebeat
my @restart_cmd = ('/etc/init.d/filebeat', 'restart');
print "正在为 $webHosts[$i] 重启Filebeat...\n";
my $restart_output = $ssh->capture({stdin_data => "$pass\n"}, 
                                   'sudo', '-Sk', '-p', '', 
                                   @restart_cmd);
print "Filebeat当前状态: $restart_output\n\n";

# 实时查看Filebeat日志
my ($log_fh, $log_pid) = $ssh->pipe_out({stdin_data => "$pass\n"}, 
                                        'sudo', '-Sk', '-p', '', 
                                        'tail', '-f', '/var/log/filebeat/filebeat');

print "开始流式输出Filebeat日志...\n";
while (my $log_line = <$log_fh>) {
    print $log_line;
}

close $log_fh;
waitpid $log_pid, 0;

内容的提问来源于stack exchange,提问作者Daksha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:44:56