2016-03-05 57 views
6

ssh経由でリモートシェル上で複数のコマンドを実行するプログラム(Windows 7のPython 3.x)を書きたいと思います。 paramikosのexec_command()関数を見た後、コマンドが環境変数に依存する(以前のコマンドで設定されている)ので、使用できないプログラム中の異なる時刻に実行されるので、1つのexec_command()呼び出しに連結されます。Paramikoを使ってPythonでsshを使って対話型シェルを実装しますか?

このように、私は同じチャネルでコマンドを実行したいです。私はに見えた次のオプションがparamikos使用して対話型シェルを実行してinvoke_shell()関数:

ssh = paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(host, username=user, password=psw, port=22) 

channel = ssh.invoke_shell() 

out = channel.recv(9999) 

channel.send('cd mivne_final\n') 
channel.send('ls\n') 

while not channel.recv_ready(): 
    time.sleep(3) 

out = channel.recv(9999) 
print(out.decode("ascii")) 

channel.send('cd ..\n') 
channel.send('cd or_fail\n') 
channel.send('ls\n') 

while not channel.recv_ready(): 
    time.sleep(3) 

out = channel.recv(9999) 
print(out.decode("ascii")) 

channel.send('cd ..\n') 
channel.send('cd simulator\n') 
channel.send('ls\n') 

while not channel.recv_ready(): 
    time.sleep(3) 

out = channel.recv(9999) 
print(out.decode("ascii")) 

ssh.close() 

をこのコードのいくつかの問題があります。

  1. は、最初の 『印刷』は必ずしも印刷を行います'ls'出力(ときどき2番目の 'print'にのみ出力されます)。
  2. 最初の 'cd'と 'ls'コマンドは常に出力にあります(出力の一部として 'recv'コマンドで取得します)。次の 'cd'と 'ls'コマンドはすべてときどき印刷され、ときどき印刷されないことがあります。
  3. 2番目と3番目の 'cd'と 'ls'コマンド(印刷時)は常に最初の 'ls'出力の前に表示されます。

私はこの「非決定主義」と混同し、あなたの助けに非常に感謝します。私は基本的にすべてのコードを使用して、ちょうどループのために追加している

+0

これは実際にはPythonコードであると仮定して、少数のフォロワーとタグをPythonタグで置き換えると、より多くの助けになるでしょう。がんばろう。 – shellter

+0

'paramiko'を使う必要がありますか?私は 'ファブリック 'で作業するほうがはるかに簡単だと分かった。 'user'、' password'、 'host_string'のような' env'変数を設定してから、リモートホストからファイルをダウンロードする '' get''や ''ファイルを送る ''や ''実行するコマンドを発行する。 'run( 'cd .. && cd simulator && ls')'のようにコマンドをチェーンすることができます。 – kchomski

+0

@kchomski残念ながら、fabricはpython 3.xと互換性がないので、オプションではありません。とにかく、私が見たものから、Fabricはparamikoへのラッパーに過ぎず、同じチャンネルで「非連鎖」コマンドを実行させません。最終的にシェルコマンドの間で実行したいと思うロジックがたくさんあります。 – misha

答えて

8
import paramiko 
import re 


class ShellHandler: 

    def __init__(self, host, user, psw): 
     self.ssh = paramiko.SSHClient() 
     self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
     self.ssh.connect(host, username=user, password=psw, port=22) 

     channel = self.ssh.invoke_shell() 
     self.stdin = channel.makefile('wb') 
     self.stdout = channel.makefile('r') 

    def __del__(self): 
     self.ssh.close() 

    def execute(self, cmd): 
     """ 

     :param cmd: the command to be executed on the remote computer 
     :examples: execute('ls') 
        execute('finger') 
        execute('cd folder_name') 
     """ 
     cmd = cmd.strip('\n') 
     self.stdin.write(cmd + '\n') 
     finish = 'end of stdOUT buffer. finished with exit status' 
     echo_cmd = 'echo {} $?'.format(finish) 
     self.stdin.write(echo_cmd + '\n') 
     shin = self.stdin 
     self.stdin.flush() 

     shout = [] 
     sherr = [] 
     exit_status = 0 
     for line in self.stdout: 
      if str(line).startswith(cmd) or str(line).startswith(echo_cmd): 
       # up for now filled with shell junk from stdin 
       shout = [] 
      elif str(line).startswith(finish): 
       # our finish command ends with the exit status 
       exit_status = int(str(line).rsplit(maxsplit=1)[1]) 
       if exit_status: 
        # stderr is combined with stdout. 
        # thus, swap sherr with shout in a case of failure. 
        sherr = shout 
        shout = [] 
       break 
      else: 
       # get rid of 'coloring and formatting' special characters 
       shout.append(re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]').sub('', line). 
          replace('\b', '').replace('\r', '')) 

     # first and last lines of shout/sherr contain a prompt 
     if shout and echo_cmd in shout[-1]: 
      shout.pop() 
     if shout and cmd in shout[0]: 
      shout.pop(0) 
     if sherr and echo_cmd in sherr[-1]: 
      sherr.pop() 
     if sherr and cmd in sherr[0]: 
      sherr.pop(0) 

     return shin, shout, sherr 
+0

execute()に複数のコマンドを送信するにはどうすればよいですか?私はforループを実行しようとしました:forコマンドのコマンド:object.execute(command)コマンドのリストについては、2つのコマンドしか実行しないので、シェルを再起動する必要があります。 – magicsword

+0

コードを表示できますか? – misha

+0

私のコマンドでstdoutとstderrの両方が生成され、それらを別々のファイルにしたいのですが? –

0

commands = ["ls","command2","command3"] 
conn_one = ShellHandler(host,name,pwd) 
for command in commands: 
     conn_one.execute(command) 

それは正しい出力をコマンドの2を実行しますが、それはただそこに座っています。私はデルにコードのどこかに電話する必要があるのだろうかと思っています。

+0

3番目のコマンドでユーザーからの対話型入力が必要な場合がありますか?何のコマンドを実行しようとしていますか? – misha

+0

返されないようです。私が入っていれば、間違っている= conn_one.execute(コマンド)print(in、out、err)私は何も戻って来ない。ループに戻るためにコード内でssh.close()を呼び出すはずですか? – magicsword

+0

いいえ、あなたはclose()を呼び出すべきではありません。実行しようとしているコマンドを正確に教えてください。 – misha

関連する問題