用 Python 在远程机器上执行命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28411960/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 03:14:08  来源:igfitidea点击:

Execute a command on Remote Machine in Python

pythonubuntuterminaltkinterparamiko

提问by Irfan Ghaffar7

I am writing a program in python on Ubuntu, to execute a command ls -lon RaspberryPi, connect with Network.

我正在 Ubuntu 上用 python 编写程序,ls -l在 RaspberryPi 上执行命令,连接网络。

Can anybody guide me on how do I do that?

有人可以指导我如何做到这一点吗?

采纳答案by Igor Hatarist

Sure, there are several ways to do it!

当然,有几种方法可以做到!

Let's say you've got a Raspberry Pi on a raspberry.lanhost and your username is irfan.

假设您在raspberry.lan主机上有一个 Raspberry Pi ,您的用户名是irfan.

subprocess

子流程

It's the default Python library that runs commands.
You can make it run sshand do whatever you need on a remote server.

它是运行命令的默认 Python 库。
您可以让它ssh在远程服务器上运行并执行您需要的任何操作。

scrat has it covered in his answer. You definitely should do this if you don't want to use any third-party libraries.

scrat在他的回答中已经说明了这一点。如果您不想使用任何第三方库,您绝对应该这样做。

You can also automate the password/passphrase entering using pexpect.

您还可以使用 自动输入密码/密码pexpect

paramiko

帕拉米科

paramikois a third-party library that adds SSH-protocol support, so it can work like an SSH-client.

paramiko是一个添加 SSH 协议支持的第三方库,因此它可以像 SSH 客户端一样工作。

The example code that would connect to the server, execute and grab the results of the ls -lcommand would look like that:

连接到服务器、执行并获取ls -l命令结果的示例代码如下所示:

import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('raspberry.lan', username='irfan', password='my_strong_password')

stdin, stdout, stderr = client.exec_command('ls -l')

for line in stdout:
    print line.strip('\n')

client.close()

fabric

织物

You can also achieve it using fabric.
Fabric is a deployment tool which executes various commands on remote servers.

您也可以使用fabric.
Fabric 是一个部署工具,可以在远程服务器上执行各种命令。

It's often used to run stuff on a remote server, so you could easily put your latest version of the web application, restart a web-server and whatnot with a single command. Actually, you can run the same command on multiple servers, which is awesome!

它通常用于在远程服务器上运行东西,因此您可以轻松地放置最新版本的 Web 应用程序,重新启动 Web 服务器等等。实际上,您可以在多个服务器上运行相同的命令,这太棒了!

Though it was made as a deploying and remote management tool, you still can use it to execute basic commands.

尽管它是作为部署和远程管理工具制作的,但您仍然可以使用它来执行基本命令。

# fabfile.py
from fabric.api import *

def list_files():
    with cd('/'):  # change the directory to '/'
        result = run('ls -l')  # run a 'ls -l' command
        # you can do something with the result here,
        # though it will still be displayed in fabric itself.

It's like typing cd /and ls -lin the remote server, so you'll get the list of directories in your root folder.

这就像在远程服务器中键入cd /和一样ls -l,因此您将获得根文件夹中的目录列表。

Then run in the shell:

然后在shell中运行:

fab list_files

It will prompt for an server address:

它将提示输入服务器地址:

No hosts found. Please specify (single) host string for connection: [email protected]


A quick note: You can also assign a username and a host right in a fabcommand:

快速说明:您还可以在fab命令中分配用户名和主机权限:

fab list_files -U irfan -H raspberry.lan

Or you could put a host into the env.hostsvariable in your fabfile. Here's how to do it.

或者您可以将主机放入env.hostsfabfile 中的变量中。这是如何做到的



Then you'll be prompted for a SSH password:

然后系统会提示您输入 SSH 密码:

[[email protected]] run: ls -l
[[email protected]] Login password for 'irfan':

And then the command will be ran successfully.

然后命令将成功运行。

[[email protected]] out: total 84
[[email protected]] out: drwxr-xr-x   2 root root  4096 Feb  9 05:54 bin
[[email protected]] out: drwxr-xr-x   3 root root  4096 Dec 19 08:19 boot
...

回答by sashab

Simple example from here:

来自这里的简单示例:

import subprocess
import sys

HOST="www.example.org"
# Ports are handled in ~/.ssh/config since we use OpenSSH
COMMAND="uname -a"

ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
                       shell=False,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
    error = ssh.stderr.readlines()
    print >>sys.stderr, "ERROR: %s" % error
else:
    print result

It does exactly what you want: connects over ssh, executes command, returns output. No third party library needed.

它完全符合您的要求:通过 ssh 连接、执行命令、返回输出。不需要第三方库。

回答by Sagar Jagnade

You may use below method with linux/ Unix 's built in ssh command.

您可以将以下方法与 linux/Unix 的内置 ssh 命令一起使用。

   import os
   os.system('ssh username@ip  bash < local_script.sh >> /local/path/output.txt 2>&1')
   os.system('ssh username@ip  python < local_program.py >> /local/path/output.txt 2>&1')

回答by Sagar Jagnade

Paramiko module can be used to run multiple commands by invoking shell. Here I created class to invoke ssh shell

Paramiko 模块可用于通过调用 shell 来运行多个命令。在这里我创建了类来调用 ssh shell

class ShellHandler:

类 ShellHandler:

def __init__(self, host, user, psw):
    logger.debug("Initialising instance of ShellHandler host:{0}".format(host))
    try:
        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.ssh.connect(host, username=user, password=psw, port=22)
        self.channel = self.ssh.invoke_shell()
    except:
        logger.error("Error Creating ssh connection to {0}".format(host))
        logger.error("Exiting ShellHandler")
        return
    self.psw=psw
    self.stdin = self.channel.makefile('wb')
    self.stdout = self.channel.makefile('r')
    self.host=host
    time.sleep(2)

    while not self.channel.recv_ready():
        time.sleep(2)
    self.initialprompt=""
    while self.channel.recv_ready():

        rl, wl, xl = select.select([ self.stdout.channel ], [ ], [ ], 0.0)
        if len(rl) > 0:
            tmp = self.stdout.channel.recv(24)
            self.initialprompt=self.initialprompt+str(tmp.decode())



def __del__(self):
    self.ssh.close()
    logger.info("closed connection to {0}".format(self.host))

def execute(self, cmd):
    cmd = cmd.strip('\n')
    self.stdin.write(cmd + '\n')
    #self.stdin.write(self.psw +'\n')
    self.stdin.flush()
    time.sleep(1)
    while not self.stdout.channel.recv_ready():
        time.sleep(2)
        logger.debug("Waiting for recv_ready")

    output=""
    while self.channel.recv_ready():
        rl, wl, xl = select.select([ self.stdout.channel ], [ ], [ ], 0.0)
        if len(rl) > 0:
            tmp = self.stdout.channel.recv(24)
            output=output+str(tmp.decode())
    return output

If creating different shell each time does not matter to you then you can use method as below.

如果每次创建不同的外壳对您来说无关紧要,那么您可以使用以下方法。

def run_cmd(self,cmd):
    try:
        cmd=cmd+'\n'
        #self.ssh.settimeout(60)
        stdin,stdout,stderr=self.ssh.exec_command(cmd)
        while not stdout.channel.eof_received:
           time.sleep(3)
           logger.debug("Waiting for eof_received")
        out=""
        while stdout.channel.recv_ready():
            err=stderr.read()
            if err:
                print("Error: ",my_hostname, str(err))
                return False 

            out=out+stdout.read()
        if out:
               return out 

    except:
        error=sys.exc_info()
        logger.error(error)
        return False