8

Ruby witch net::ssh で、リモート Linux マシンでコマンドを 1 つずつ実行し、すべてをログに記録するコードを書きたい (Linux マシンではコマンド、stdout、stderr と呼ばれる)。

だから私は関数を書く:

  def rs(ssh,cmds)
    cmds.each do |cmd|
      log.debug "[SSH>] #{cmd}"
      ssh.exec!(cmd) do |ch, stream, data|    
        log.debug "[SSH:#{stream}>] #{data}"            
      end  
    end
  end

たとえば、リモートLinuxで新しいフォルダーとファイルを作成したい場合:「./verylongdirname/anotherlongdirname/a.txt」、そのディレクトリにファイルをリストし、そこでfirefoxを見つけます(これは少しばかげています:P)ので、呼び出します上記の手順は次のとおりです。

Net::SSH.start(host, user, :password => pass) do |ssh|  

  cmds=["mkdir verylongdirname", \                                 #1
        "cd verylongdirname; mkdir anotherlongdirname, \           #2
        "cd verylongdirname/anotherlongdirname; touch a.txt", \    #3
        "cd verylongdirname/anotherlongdirname; ls -la", \         #4
        "cd verylongdirname/anotherlongdirname; find ./ firefox"   #5 that command send error to stderr.
        ]

  rs(ssh,cmds)   # HERE we call our function

  ssh.loop
end

上記のコードを実行すると、#1、#2、#3、#4、#5 の実行コマンドに関する完全なログ ウィッチ情報が得られます。問題は、cmds 配列からの実行コマンド間の Linux の状態が保存されないことです (したがって、適切なコマンドを実行する前に「cd」ステートメントを繰り返す必要があります)。そして、私はそれに満足していません。

私の目的は、次のような cmds テーブルを持つことです。

  cmds=["mkdir verylongdirname", \     #1
        "cd verylongdirname", \        
        "mkdir anotherlongdirname", \  #2
        "cd anotherlongdirname", \
        "touch a.txt", \               #3
        "ls -la", \                    #4
        "find ./ firefox"]             #5

ご覧のとおり、各コマンドの実行間の状態は Linux マシンに保存されます (適切なコマンドを実行する前に、適切な「cd」ステートメントを繰り返す必要はありません)。"rs(ssh,cmds)" 手順を変更して、以前のようにすべて (コマンド、標準出力、標準入力) をログに記録するにはどうすればよいですか?

4

4 に答える 4

4

おそらく、リモート シェルを開く代わりに ssh チャネルで試してみてください。接続が開いたままになるため、コマンド間の状態を保持する必要があります。

http://net-ssh.github.com/ssh/v1/chapter-5.html

少し異なるアプローチで同様のことを行う記事もあります。

http://drnicwilliams.com/2006/09/22/remote-shell-with-ruby/

編集1

Ok。あなたの言っていることがわかります。SyncShellNet::SSH 2.0 から削除されました。しかし、私はこれを見つけました。これは、ほとんど何をしたかのように見えますSyncShell:

http://net-ssh-telnet.rubyforge.org/

例:

s = Net::SSH.start(host, user)
t = Net::SSH::Telnet.new("Session" => s, "Prompt" => %r{^myprompt :})
puts t.cmd("cd /tmp")  
puts t.cmd("ls")       # <- Lists contents of /tmp

つまり、リモート シェル環境のptyNet::SSH::Telnetで実行されるため、同期的であり、状態が保持されます。正しいプロンプト検出を設定することを忘れないでください。そうしないと、Net::SSH::Telnet呼び出すとハングしたように見えます (プロンプトを見つけようとしています)。

于 2011-07-24T13:53:05.310 に答える
2

わかりました、最後に@Casperの助けを借りて、手順を取得します(誰かが使用するかもしれません):

  # Remote command execution
  # t=net::ssh:telnet, c="command_string"
  def cmd(t,c)    
    first=true
    d=''    
    # We send command via SSH and read output piece by piece (in 'cm' variable)
    t.cmd(c) do |cm|       
      # below we cleaning up output piece (becouse it have strange chars)     
      d << cm.gsub(/\e\].*?\a/,"").gsub(/\e\[.*?m/,"").gsub(/\r/,"")     
      # when we read entire line(composed of many pieces) we write it to log
      if d =~ /(^.*?)\n(.*)$/m
        if first ; 
          # instead of the first line (which has repeated commands) we log commands 'c'
          @log.info "[SSH]>"+c; 
          first=false
        else
          @log.info "[SSH] "+$1; 
        end
        d=$2        
      end      
    end

    # We print lines that were at the end (in last piece)
    d.each_line do |l|
      @log.info "[SSH] "+l.chomp      
    end
  end

そして、それをコードで呼び出します。

#!/usr/bin/env ruby

require 'rubygems'

require 'net/ssh'

require 'net/ssh/telnet'

require 'log4r'
...
...
...
Net::SSH.start(host, user, :password => pass) do |ssh|  
  t = Net::SSH::Telnet.new("Session" => ssh)
  cmd(t,"cd /")
  cmd(t,"ls -la")
  cmd(t,"find ./ firefox")  
end

ありがとさよなら。

于 2011-07-26T16:07:36.477 に答える
2

代わりにパイプを使用できます。

require "open3"

SERVER = "..."
BASH_PATH = "/bin/bash"

BASH_REMOTE = lambda do |command|
  Open3.popen3("ssh #{SERVER} #{BASH_PATH}") do |stdin, stdout, stderr|
    stdin.puts command
    stdin.close_write
    puts "STDOUT:", stdout.read
    puts "STDERR:", stderr.read
  end
end

BASH_REMOTE["ls /"]
BASH_REMOTE["ls /no_such_file"]
于 2011-07-24T21:18:32.807 に答える
0

Net/ssh のラッパーはこちらの記事ですhttp://ruby-lang.info/blog/virtual-file-system-b3g

ソースhttps://github.com/alexeypetrushin/vfs

すべてのコマンドをログに記録するには、Box.bash メソッドを上書きしてそこにログを追加するだけです

于 2011-08-05T22:22:42.127 に答える