How to display shell command progress indicators via ssh

I have a script that should simulate ffmpeg on my local machine by sending a command to the remote machine, running it there, and then returning the results. (see previous stack overflow 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

now my problem is

ssh.exec!(cmd)

I want to display cmd output to a local user in real time . But by doing it

puts ssh.exec!(cmd)

I get the result only after the completion of the command. How do I change the code to make this work?

+3
source share
2 answers

From ri Net::SSH::start:

 -------------------------------------------------------- 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

:

user@server% 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"

:

user@local% 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
user@local% ./client.rb
[:data, "hello\n"]
[:data, "earn\n"]
[:data, "more\n"]
[:data, "sessions\n"]
[:data, "by\n"]
[:data, "sleaving\n"]
[:data, "goodbye\n"]

, .

, - , , , .

+4

Ruby, "\ r" char. , . :

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

, , - :

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

, stdout, (STDOUT.flush), Ruby - ( STDOUT) ( ):

STDOUT.sync = true

, , , "IO.fsync". , .

+7

Source: https://habr.com/ru/post/1708483/


All Articles