使用Python在ssh上执行命令

fre*_*ley 113 python ssh

我正在编写一个脚本来自动化Python中的一些命令行命令.此刻我正在打电话:

cmd = "some unix command"
retcode = subprocess.call(cmd,shell=True)
Run Code Online (Sandbox Code Playgroud)

但是我需要在远程计算机上运行一些命令.手动,我会使用ssh登录然后运行命令.我如何在Python中自动执行此操作?我需要使用(已知的)密码登录到远程机器,所以我不能只使用cmd = ssh user@remotehost,我想知道是否有一个我应该使用的模块?

sha*_*pan 176

我会把你推荐给paramiko

看到这个问题

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd_to_execute)
Run Code Online (Sandbox Code Playgroud)

  • 如果你正在使用SSH密钥,首先使用EITHER准备密钥文件:`k = paramiko.RSAKey.from_private_key_file(keyfilename)`或`k = paramiko.DSSKey.from_private_key_file(keyfilename)`那么`ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy( ))``最后`ssh..connect(hostname = host,username = user,pkey = k)`. (10认同)
  • 作为Paramiko的长期用户(但不是专家),我可以建议使用Paramiko但你应该考虑你的用例以及你愿意学习多少.Paramiko是非常低级的,你很容易陷入陷阱,在这个陷阱中你创建了一个"命令运行辅助函数"而没有完全理解你正在使用的代码.这意味着你可能会设计一个`def run_cmd(host,cmd):`它最初会做你想要的,但是你的需求在不断变化.您最终会更改新用例的帮助程序,这会更改旧的现有用法的行为.相应地计划. (6认同)
  • 对于未知的主机错误,请执行以下操作:ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) (3认同)
  • 这里的假设是paramiko和(open)ssh一样安全.是吗? (2认同)

pow*_*rox 45

或者你可以使用commands.getstatusoutput:

   commands.getstatusoutput("ssh machine 1 'your script'")
Run Code Online (Sandbox Code Playgroud)

我广泛使用它,效果很好.

在Python 2.6+中,使用subprocess.check_output.

  • +1是一个简单的内置方法.在我目前的设置中,我不想添加Python库,因此您的建议很有价值,也非常简单. (3认同)
  • 只需确保您的远程主机设置为无密码ssh,否则,您必须执行其他操作来管理身份验证 (3认同)
  • @powerrox那些“其他东西”是什么? (2认同)
  • @TimS.您可能必须通过适合您的设置的任何方式包括身份验证处理.我用过期望在提示符下输入密码.然后有这个线程与其他解决方案:http://unix.stackexchange.com/questions/147329/answer-password-prompt-programmatically-via-shell-script (2认同)

Ron*_*acc 43

把事情简单化。不需要库。

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()
Run Code Online (Sandbox Code Playgroud)

  • 如果你的 ssh 命令要求输入密码,你将如何在 Python 文件中提供密码? (17认同)
  • 您还可以使用“sshpass -p {密码} ssh {用户}@{ip}” (6认同)
  • 子流程是自动化领域的瑞士军刀。然后,您可以将 Python 与 shell 脚本、sed、awk、grep 等无限可能性结合起来。是的,你都可以在 Python 中完成,但是在 python 中的某个地方运行 grep 不是很好吗 - 好吧,你可以。 (3认同)
  • @BeingSuman 您可以使用 SSH 密钥身份验证。虽然我猜你已经明白了。 (3认同)
  • @BeingSuman `f"echo {password} | ssh {user}@{host} {cmd}"`。当然,只有在提示用户时才安全。 (2认同)
  • 每个命令的新连接都不好。 (2认同)

sup*_*ghs 27

你看过Fabric吗?它允许您使用python通过SSH执行各种远程操作.


Mic*_*son 16

我发现paramiko有点太低级了,而且Fabric不太适合用作库,所以我把我自己的库叫做spur,使用paramiko来实现一个稍微好一点的界面:

import spur

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

如果你需要在shell中运行:

shell.run(["sh", "-c", "echo -n hello"])
Run Code Online (Sandbox Code Playgroud)

  • 我决定尝试'刺激'.您生成其他shell命令,最终得到:'mkdir'>/dev/null 2>&1; echo $?; exec'mkdir''-p''/ data/rpmupdate/20130207142923'.我想访问一个普通的`exec_command`.还缺少运行后台任务的能力:`nohup ./bin/rpmbuildpackages </ dev/null>&/ dev/null&`.例如,我使用模板生成一个zsh脚本(rpmbuildpackages)然后我只是让它在机器上运行.也许能够监控这样的后台工作也很好(在某些〜/ .spur中保存PID). (2认同)

Ped*_*ito 11

接受的答案对我不起作用,这是我使用的:

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())
Run Code Online (Sandbox Code Playgroud)
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
...
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用sshpass

import subprocess
cmd = """ sshpass -p "myPas$" ssh user@d.d.d.d -p 12345 'my command; exit' """
print( subprocess.getoutput(cmd) )
Run Code Online (Sandbox Code Playgroud)

参考:

  1. https://github.com/onyxfish/relay/issues/11
  2. /sf/answers/4271166441/

笔记:

  1. 只需确保通过 ssh ( ssh root@ip) 手动连接到远程系统至少一次并接受公钥,这很多时候是无法使用paramiko其他自动ssh脚本进行连接的原因。


Ale*_*kov 9

添加额外的行后,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)
Run Code Online (Sandbox Code Playgroud)

确保已安装 paramiko 包。解决方案的原始来源:Source


IAm*_*ade 8

所有人都已经说过(推荐)使用paramiko,我只是共享一个python代码(API可能会说),它允许你一次执行多个命令.

在不同节点上执行命令: Commands().run_cmd(host_ip, list_of_commands)

您将看到一个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:])
Run Code Online (Sandbox Code Playgroud)

谢谢!