使用Python在SSH上执行命令


136

我正在编写一个脚本来自动化Python中的某些命令行命令。目前,我正在打电话:

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

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

Answers:


201

我会带你去paramiko

看到这个问题

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

1
如果交换了ssh密钥怎么办?
阿迪特(Ardit)

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

7
作为Paramiko的长期用户(但不是专家),我建议您使用Paramiko,但您应该考虑您的用例以及您愿意学习多少。Paramiko是非常低级的,您很容易陷入陷阱,在其中无需完全了解所使用的代码即可创建“命令运行助手功能”。这意味着您可能会设计一个a def run_cmd(host, cmd):,起初您想要什么,但是您的需求会不断变化。您最终将更改新用例的帮助程序,这将更改旧的现有用法的行为。制定相应的计划。
Scott Prive

3
对于未知的主机错误,请执行:ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())在
Nemo

48

或者,您可以只使用commands.getstatusoutput

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

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

在Python 2.6+中,使用subprocess.check_output


4
+1是一种不错的简单内置方法。在我当前的设置中,我不想添加Python库,因此您的建议很有价值,也很简单。
菲利普·基恩斯

3
只需确保为远程主机设置了无密码的ssh,否则,您必须做其他事情来管理身份验证
powerrox 2014年

subprocess.check_output-很好的解决方案!
蒂姆·S.

2
@powerrox那些“其他东西”是什么?
ealeon

2
@TimS。您可能需要通过适合您的设置的任何方式包括身份验证处理。我曾经期望在提示符下输入密码。再有就是这个线程与其他解决方案:unix.stackexchange.com/questions/147329/...
powerrox


18

我发现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

如果需要在外壳中运行:

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

2
我决定尝试spur。您生成其他shell命令,最终得到: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

1
spur显然仅适用于UNIX系统,因为它依赖termios。有人知道Windows的良好库吗?
加百利

并非完全正确:如果您使用预编译的安装程序,则可以安装paramiko和spur。我自己做的…
拉韦米尔2014年

@Gabriel:最近的发行版之一应该改进了对Windows的支持。如果仍然无法使用,请随时提出问题。
Michael Williamson

@davidlt:构建时SshShell,现在可以选择设置外壳类型。如果通过传入使用了最少的shell shell_type=spur.ssh.ShellTypes.minimal,则仅发送raw命令。对于Spur来说,直接执行后台任务感觉有点超出范围,但是您应该能够通过调用shell(例如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与无数种可能性结合起来,例如shell脚本,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)

您将看到一个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:])

谢谢!



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
一个包装纸一个包装纸..不错:)
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
与其以更好的格式重新发布两天前的答案,不如编辑较旧的答案并改善其格式?
蛇charmerb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.