Pythonを使用してSSH経由でコマンドを実行する


136

Pythonでいくつかのコマンドラインコマンドを自動化するスクリプトを書いています。現在、私はこうして電話をかけています:

cmd = "some unix command"
retcode = subprocess.call(cmd,shell=True)

ただし、リモートマシンでいくつかのコマンドを実行する必要があります。手動で、sshを使用してログインし、コマンドを実行します。Pythonでこれを自動化するにはどうすればよいですか?(既知の)パスワードを使用してリモートマシンにログインする必要があるためcmd = ssh user@remotehost、を使用できません。使用する必要があるモジュールがあるかどうか疑問に思います。

回答:


201

パラミコを紹介します

この質問を

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd_to_execute)

3
ここでの前提は、paramikoが(open)sshと同じくらい安全であることです。それは...ですか?
user239558 2015

1
ssh-keyが交換された場合はどうなりますか?
Ardit 2016年

19
SSHキーを使用している場合は、まずEITHER:k = paramiko.RSAKey.from_private_key_file(keyfilename)OR k = paramiko.DSSKey.from_private_key_file(keyfilename)THEN を使用してキーファイルを準備し、ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())最後にを作成しssh..connect(hostname=host, username=user, pkey=k)ます。
Scott Prive 2017

7
Paramikoの長いユーザー(エキスパートではありません)として、私はParamikoの使用を提案できますが、ユースケースとどれだけ学習したいかを検討する必要があります。Paramikoは非常に低レベルであり、使用しているコードを完全に理解していなくても、簡単に「コマンド実行ヘルパー関数」を作成するという罠に陥る可能性があります。つまりdef run_cmd(host, cmd):、最初は自分がやりたいことを実行するように設計するかもしれませんが、ニーズは進化します。新しいユースケースのヘルパーを変更すると、古い既存の使用法の動作が変更されます。それに応じて計画します。
Scott Prive

3
不明なホストエラーの場合:ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())before
Nemo

49

または、単にcommands.getstatusoutputを使用できます

   commands.getstatusoutput("ssh machine 1 'your script'")

私はそれを広範囲に使用し、それは素晴らしい働きをします。

Python 2.6以降では、を使用しますsubprocess.check_output


4
素敵なシンプルな組み込みメソッドの+1。私の現在のセットアップでは、Pythonライブラリを追加したくないので、あなたの提案は非常に単純明快です。
Philip Kearns、2013年

3
リモートホストがパスワードなしのsshに設定されていることを確認してください。設定されていない場合は、認証を管理するために他のことを行う必要があります
powerrox

subprocess.check_output-素晴らしいソリューションです!
Tim S.

2
@powerroxそれらの「その他」とは何ですか?
ealeon 2015年

2
@TimS。設定に適した方法で認証の処理を含める必要がある場合があります。プロンプトでパスワードを入力することを期待して使用しました。その後、他のソリューションとこのスレッドがあります:unix.stackexchange.com/questions/147329/...
powerroxは、


18

私はparamikoが少し低すぎることがわかり、Fabricをライブラリとして使用するのに特に適していなかったため、paramikoを使用してやや優れたインターフェイスを実装するspurという独自のライブラリをまとめました。

import spur

shell = spur.SshShell(hostname="localhost", username="bob", password="password1")
result = shell.run(["echo", "-n", "hello"])
print result.output # prints hello

シェル内で実行する必要がある場合:

shell.run(["sh", "-c", "echo -n hello"])

2
やってみることにしましたspur。追加のシェルコマンドを生成すると、次のようになります。which 'mkdir'> / dev / null 2>&1; エコー$ ?; exec 'mkdir' '-p' '/ data / rpmupdate / 20130207142923'。プレーンにもアクセスしたいのですがexec_command。バックグラウンドタスクを実行する機能もありません:nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &。たとえば、テンプレートを使用してzshスクリプト(rpmbuildpackages)を生成し、それをマシンで実行したままにしておきます。おそらく、そのようなバックグラウンドジョブを監視する機能も(PIDを〜/ .spurに保存して)いいでしょう。
davidlt 2013

1
spurどうやらUNIXシステムでのみ機能するため、に依存していtermiosます。Windowsに適したライブラリを知っている人はいますか?
ガブリエル

完全に正しくはありません:プリコンパイルされたインストーラーを使用する場合、paramikoとspurをインストールできます。私は自分でやりました...
ravemir

@Gabriel:最近のリリースの1つで、Windowsのサポートが改善されているはずです。それでも機能しない場合は、お気軽に問題を開いてください。
マイケルウィリアムソン

@davidlt:を作成するときにSshShell、シェルタイプを設定するオプションが追加されました。を渡して最小限のシェルを使用するとshell_type=spur.ssh.ShellTypes.minimal、rawコマンドのみが送信されます。バックグラウンドタスクを直接実装することは、Spurの範囲から少し外れているように感じますが、シェルなどを呼び出して、説明したコマンドを実行できるはずshell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"]です。
マイケルウィリアムソン

18

単純にする。ライブラリは必要ありません。

import subprocess

subprocess.Popen("ssh {user}@{host} {cmd}".format(user=user, host=host, cmd='ls -l'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

1
サブプロセスは、自動化におけるスイスアーミーナイフです。次に、Pythonをシェルスクリプト、sed、awk、grepなどの無限の可能性と組み合わせることができます。はい、すべてPythonで実行できますが、Pythonのどこかでgrepを実行するのは素晴らしいことではありません。
Ronn Macc

12
あなたのsshコマンドがパスワードを要求する場合、どのようにそれをPythonファイルに提供しますか?
BeingSuman

1
@BeingSumanそのためにSSHキー認証を使用できます。あなたはすでにそれを理解していると思いますが。
mmrbulbul

9

すべてはすでにparamikoを使用して述べ(推奨)、私は一度に複数のコマンドを実行できるようにするpythonコード(APIと言うかもしれません)を共有しています。

別のノードでコマンドを実行するには、次のコマンドを使用します。 Commands().run_cmd(host_ip, list_of_commands)

1つのTODOが表示されます。これは、コマンドのいずれかが実行に失敗した場合に実行を停止し続けますが、その方法がわかりません。あなたの知識を共有してください

#!/usr/bin/python

import os
import sys
import select
import paramiko
import time


class Commands:
    def __init__(self, retry_time=0):
        self.retry_time = retry_time
        pass

    def run_cmd(self, host_ip, cmd_list):
        i = 0
        while True:
        # print("Trying to connect to %s (%i/%i)" % (self.host, i, self.retry_time))
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(host_ip)
            break
        except paramiko.AuthenticationException:
            print("Authentication failed when connecting to %s" % host_ip)
            sys.exit(1)
        except:
            print("Could not SSH to %s, waiting for it to start" % host_ip)
            i += 1
            time.sleep(2)

        # If we could not connect within time limit
        if i >= self.retry_time:
            print("Could not connect to %s. Giving up" % host_ip)
            sys.exit(1)
        # After connection is successful
        # Send the command
        for command in cmd_list:
            # print command
            print "> " + command
            # execute commands
            stdin, stdout, stderr = ssh.exec_command(command)
            # TODO() : if an error is thrown, stop further rules and revert back changes
            # Wait for the command to terminate
            while not stdout.channel.exit_status_ready():
                # Only print data if there is data to read in the channel
                if stdout.channel.recv_ready():
                    rl, wl, xl = select.select([ stdout.channel ], [ ], [ ], 0.0)
                    if len(rl) > 0:
                        tmp = stdout.channel.recv(1024)
                        output = tmp.decode()
                        print output

        # Close SSH connection
        ssh.close()
        return

def main(args=None):
    if args is None:
        print "arguments expected"
    else:
        # args = {'<ip_address>', <list_of_commands>}
        mytest = Commands()
        mytest.run_cmd(host_ip=args[0], cmd_list=args[1])
    return


if __name__ == "__main__":
    main(sys.argv[1:])

ありがとうございました!


4

私はparamiko a bunch(nice)とpxssh(nice)を使用しました。どちらかをお勧めします。動作は少し異なりますが、使用量のオーバーラップが比較的大きくなります。


4
pxsshへのリンクは、過去にさかのぼる良い旅です。
Oben Sonne 14

3

追加の行を追加した後、最終的にparamikoが私にとってうまくいきました。これは本当に重要な行です(3行目):

import paramiko

p = paramiko.SSHClient()
p.set_missing_host_key_policy(paramiko.AutoAddPolicy())   # This script doesn't work for me unless this line is added!
p.connect("server", port=22, username="username", password="password")
stdin, stdout, stderr = p.exec_command("your command")
opt = stdout.readlines()
opt = "".join(opt)
print(opt)

paramikoパッケージがインストールされていることを確認してください。ソリューションの元のソース:ソース


1
#Reading the Host,username,password,port from excel file
import paramiko 
import xlrd

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0,1)
Port = int(sheet.cell_value(3,1))
User = sheet.cell_value(1,1)
Pass = sheet.cell_value(2,1)

def details(Host,Port,User,Pass):
    ssh.connect(Host, Port, User, Pass)
    print('connected to ip ',Host)
    stdin, stdout, stderr = ssh.exec_command("")
    stdin.write('xcommand SystemUnit Boot Action: Restart\n')
    print('success')

details(Host,Port,User,Pass)

1

完璧に動作します...

import paramiko
import time

ssh = paramiko.SSHClient()
#ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.106.104.24', port=22, username='admin', password='')

time.sleep(5)
print('connected')
stdin, stdout, stderr = ssh.exec_command(" ")

def execute():
       stdin.write('xcommand SystemUnit Boot Action: Restart\n')
       print('success')

execute()

1

受け入れられた答えは私にはうまくいきませんでした、代わりに私が使ったものは次のとおりです:

import paramiko
import os

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# ssh.load_system_host_keys()
ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
ssh.connect("d.d.d.d", username="user", password="pass", port=22222)

ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -alrt")
exit_code = ssh_stdout.channel.recv_exit_status() # handles async exit error 

for line in ssh_stdout:
    print(line.strip())

total 44
-rw-r--r--.  1 root root  129 Dec 28  2013 .tcshrc
-rw-r--r--.  1 root root  100 Dec 28  2013 .cshrc
-rw-r--r--.  1 root root  176 Dec 28  2013 .bashrc
...

あるいは、sshpassを使用できます。

import subprocess
cmd = """ sshpass -p "myPas$" ssh user@d.d.d.d -p 22222 'my command; exit' """
print( subprocess.getoutput(cmd) )

参照:
1. https://github.com/onyxfish/relay/issues/11
2. https://stackoverflow.com/a/61016663/797495


0

見ていspurplus、私たちは周りに開発したラッパーspur型注釈といくつかのマイナーな仕掛けを提供(SFTPを再接続し、MD5 など。):https://pypi.org/project/spurplus/


1
ラッパーのラッパーのラッパー.. nice :)
Alex R

まあ、展開スクリプトを簡単なものにしたいのであれば、基礎となるツールが十分に単純/抽象的であるとは思えません。これまでのところ、リークのある抽象化は観察されていません。
marko.ristin

0

ログインしているデバイスごとにコマンドを入力するようユーザーに要求する。
以下のコードはPEP8online.comによって検証されます。

import paramiko
import xlrd
import time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0, 1)
Port = int(sheet.cell_value(3, 1))
User = sheet.cell_value(1, 1)
Pass = sheet.cell_value(2, 1)

def details(Host, Port, User, Pass):
    time.sleep(2)
    ssh.connect(Host, Port, User, Pass)
    print('connected to ip ', Host)
    stdin, stdout, stderr = ssh.exec_command("")
    x = input('Enter the command:')
    stdin.write(x)
    stdin.write('\n')
    print('success')

details(Host, Port, User, Pass)

0

以下の例では、ホスト名、ユーザー名、パスワード、ポート番号のユーザー入力が必要な場合。

  import paramiko

  ssh = paramiko.SSHClient()

  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())



  def details():

  Host = input("Enter the Hostname: ")

  Port = input("Enter the Port: ")

  User = input("Enter the Username: ")

  Pass = input("Enter the Password: ")

  ssh.connect(Host, Port, User, Pass, timeout=2)

  print('connected')

  stdin, stdout, stderr = ssh.exec_command("")

  stdin.write('xcommand SystemUnit Boot Action: Restart\n')

  print('success')

  details()

5
2日前の回答をより良いフォーマットで再投稿するのではなく、古い回答を編集してフォーマットを改善してみませんか?
snakecharmerb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.