输入密码后,Net :: SSH sudo命令挂起

我一直在尝试使用Thor编写一个小型库来帮助我快速创建新项目和站点。 我写了这个小方法:

def ssh(cmd) Net::SSH.start( server_ip, user, :port => port) do |session| session.exec cmd end end 

在需要时帮助我在远程服务器上运行快速命令。

问题是,当我需要在远程端的sudo下运行命令时,脚本似乎挂在我身上。 例如,当执行此…时

 ssh("sudo cp #{file_from_path} #{file_to_path}" ) 

该脚本将提示我输入密码

 [sudo] password for user: 

但是输入之后整个事情就变成了笨蛋。

有人会碰巧知道为什么它会完全挂起,以及我可以做些什么来在Net :: SSH(或其他替代方案)下的远程服务器上运行sudo命令?

*注意:在建议之前,我最初开始将这个库作为Capistrano下的食谱编写,直到我遇到Thor,并认为这是一个尝试它的好机会。 如果需要的话,我不反对将整个事情切换回Capistrano,但如果没有一种简单的方法在远程服务器上运行sudo命令,我会感到非常惊讶。

您可能想要尝试的第一件事是使用公钥而不是密码登录。 然后还尝试从交互式shell运行该命令。

例如:

(这部分真的取决于你的服务器/客户端软件)

 $ ssh-keygen $ scp .ssh/id-dsa.pub server: $ ssh server server$ cat id-dsa.pub >> .ssh/authorizedkeys $ scp -c "ls" 

如果密钥共享成功,这应该在没有任何提示的情况下工作。

我希望这能帮助有人搜索。 部署期间我还需要sudo (重启瘦实例)

 # deploy.rake require 'net/ssh' # INITIALIZE CONSTANTS HERE HOST = 'yourwebsite.com' USER = 'admin' PASSWORD = 'your server password' # or use ENV variables? # etc. namespace :deploy do namespace :staging do task :restart do commands = [ "cd #{PATH_TO_STAGING_APP} && git checkout master", "git reset --hard HEAD", "git pull origin master", "bundle install --without test development", "sudo thin restart -C /etc/thin/#{STAGING_APP}.yml" ] Net::SSH.start(HOST, USER, :password => PASSWORD) do |ssh| ssh.open_channel do |channel| channel.request_pty do |ch, success| if success puts "Successfully obtained pty" else puts "Could not obtain pty" end end channel.exec(commands.join(';')) do |ch, success| abort "Could not execute commands!" unless success channel.on_data do |ch, data| puts "#{data}" channel.send_data "#{PASSWORD}\n" if data =~ /password/ end channel.on_extended_data do |ch, type, data| puts "stderr: #{data}" end channel.on_close do |ch| puts "Channel is closing!" end end end ssh.loop end end end end 

请注意,一个通道只能执行一个命令。 因此我将命令与commands.join(';')链接在一起

参考: Net :: SSH :: Connection :: Channel

这是一个可能的解决方案:

 def ssh(cmd) Net::SSH.start( server_ip, user, :port => port) do |session| result = nil session.exec!(cmd) do |channel, stream, data| if data =~ /^\[sudo\] password for user:/ channel.send_data 'your_sudo_password' else result << data end end result # content of 'cmd' result end end 

但是使用此解决方案,您可以在某个脚本文件中明确写入root密码...

可以使用net/ssh进行设置,但这确实太费力了,只需像这样执行ssh命令:

 system("ssh", "-t", "#{user}@#{host}", "sudo cp #{file_from_path} #{file_to_path}") 

-t意味着分配一个tty。 没有它它仍然可以工作,但你的密码将被清楚地看到。

(我假设您打算手动输入sudo密码。如果没有,请按授权密钥方式)。

我通过添加这个来欺骗:

 sudouser ALL=(ALL:ALL) NOPASSWD: ALL 

/etc/sudoers

另外,编辑时务必使用visudo !!!

实际上最后,我做了一些非常类似于Riba的建议(尽管他/她的代码更好更智能,我认为)

 def ssh(env, cmd, opts={}) Net::SSH.start( config[env]["ip"], config[env]["user"], :port => config[env]["port"]) do |session| cmd = "sudo #{cmd}" if opts[:sudo] print cmd session.exec cmd end end