2009-05-16 14 views
3

ローカルマシンのffmpegを模倣するスクリプトがあります。リモートマシンにコマンドを送信して実行し、結果を返します。私はリアルタイムにローカルユーザーへのCMDの出力を表示したいシェルコマンドからssh経由でプログレスバーを表示するにはどうすればいいですか

ssh.exec!(cmd) 

で (previous stackoverflow question.を参照)

#!/usr/bin/env ruby 

require 'rubygems' 
require 'net/ssh' 
require 'net/sftp' 
require 'highline/import' 


file = ARGV[ ARGV.index('-i') + 1] if ARGV.include?('-i') 
puts 'No input file specified' unless file; 

host = "10.0.0.10" 
user = "user" 
prod = "new-#{file}"    # product filename (call it <file>-new) 
rpath = "/home/#{user}/.rffmpeg" # remote computer operating directory 
rfile = "#{rpath}/#{file}"   # remote filename 
rprod = "#{rpath}/#{prod}"   # remote product 
cmd = "ffmpeg -i #{rfile} #{rprod}"# remote command, constructed 

pass = ask("Password: ") { |q| q.echo = false } # password from stdin 

Net::SSH.start(host, user) do |ssh| 
     ssh.sftp.connect do |sftp| 

       # upload local 'file' to remote 'rfile' 
       sftp.upload!(file, rfile) 

       # run remote command 'cmd' to produce 'rprod' 
       ssh.exec!(cmd) 

       # download remote 'rprod' to local 'prod' 
       sftp.download!(rprod, prod) 
     end 
end 

は今、私の問題があります。しかし、それを作る

puts ssh.exec!(cmd) 

私はコマンドの実行が終了した後に結果を得るだけです。この作業を行うためにコードをどのように変更する必要がありますか? ri Net::SSH::startから

答えて

4

-------------------------------------------------------- Net::SSH::start 
     Net::SSH::start(host, user, options={}, &block) {|connection| ...} 
------------------------------------------------------------------------ 
     The standard means of starting a new SSH connection. When used with 
     a block, the connection will be closed when the block terminates, 
     otherwise the connection will just be returned. The yielded (or 
     returned) value will be an instance of 
     Net::SSH::Connection::Session (q.v.). (See also 
     Net::SSH::Connection::Channel and Net::SSH::Service::Forward.) 

     Net::SSH.start("host", "user") do |ssh| 
      ssh.exec! "cp /some/file /another/location" 
      hostname = ssh.exec!("hostname") 

      ssh.open_channel do |ch| 
      ch.exec "sudo -p 'sudo password: ' ls" do |ch, success| 
       abort "could not execute sudo ls" unless success 

       ch.on_data do |ch, data| 
       print data 
       if data =~ /sudo password:/
        ch.send_data("password\n") 
       end 
       end 
      end 
      end 

      ssh.loop 
     end 

あなたは#open_channel

を使用して、よりインタラクティブ得ることができるようなので、それが見えますここではいくつかのサンプルコードです:

[email protected]% cat echo.rb 
#! /usr/local/bin/ruby 
def putsf s 
    puts s 
    STDOUT.flush 
end 
putsf "hello" 
5.times do 
     putsf gets.chomp 
end 
putsf "goodbye" 

そして、あなたのローカルマシン上:

[email protected]% cat client.rb 
#! /usr/local/bin/ruby 
require 'rubygems' 
require 'net/ssh' 
words = %w{ earn more sessions by sleaving } 
index = 0; 
Net::SSH.start('server', 'user') do |ssh| 
    ssh.open_channel do |ch| 
    ch.exec './echo.rb' do |ch, success| 
     abort "could not execute ./echo.rb" unless success 

     ch.on_data do |ch, data| 
     p [:data, data] 
     index %= words.size 
     ch.send_data(words[index] + "\n") 
     index += 1 
     end 
    end 
    end 
end 
[email protected]% ./client.rb 
[:data, "hello\n"] 
[:data, "earn\n"] 
[:data, "more\n"] 
[:data, "sessions\n"] 
[:data, "by\n"] 
[:data, "sleaving\n"] 
[:data, "goodbye\n"] 

このように、実行中のプロセスとやり取りすることができます。

入力を要求する前に実行中のプロセスが出力をフラッシュすることが重要です。そうしないと、チャネルがフラッシュされていない出力を受け取っていない可能性があるため、プログラムがハングアップする可能性があります。

+0

進行状況バーは正しく表示されませんでしたか?右? – Stefan

7

質問の表示側で、Rubyで "\ r"文字列を使用して更新プログレスバーを生成することができます。これにより、現在の行の先頭に戻り、書き直すことができます。たとえば、次のように

1.upto(100) { |i| sleep 0.05; print "\rPercent Complete #{i}%"} 

それともあなたは、単にこれに似た何かをすることができ、画面全体のプログレスバーをしたい場合:前あたりの出力をフラッシュに加えて、標準出力に関連し、また

1.upto(50) { sleep 0.05; print "|"} 

を例(STDOUT.flush)、あなたは自動的に同期(基本的に内部バッファリングをオフにします)を書き込み、関連するデバイスとIOバッファ(この場合はSTDOUT)への書き込みを行うためにルビーを依頼することができます。

STDOUT.sync = true 

また、私はが時々フラッシュが私のために働かないことを、私は代わりに "IO.fsync"を使用することがわかります。私にとっては、ほとんどがファイルシステムの仕事に関連していましたが、それは知る価値があります。

関連する問題