Execute a command on Remote Machine in Python

后端 未结 4 1113
死守一世寂寞
死守一世寂寞 2020-12-02 10:53

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

Can anybody guide me on how do I do that?

相关标签:
4条回答
  • 2020-12-02 11:17

    Sure, there are several ways to do it!

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

    subprocess

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

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

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

    paramiko

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

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

    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.

    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!

    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 -l in the remote server, so you'll get the list of directories in your root folder.

    Then run in the shell:

    fab list_files
    

    It will prompt for an server address:

    No hosts found. Please specify (single) host string for connection: irfan@raspberry.lan
    

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

    fab list_files -U irfan -H raspberry.lan
    

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


    Then you'll be prompted for a SSH password:

    [irfan@raspberry.lan] run: ls -l
    [irfan@raspberry.lan] Login password for 'irfan':
    

    And then the command will be ran successfully.

    [irfan@raspberry.lan] out: total 84
    [irfan@raspberry.lan] out: drwxr-xr-x   2 root root  4096 Feb  9 05:54 bin
    [irfan@raspberry.lan] out: drwxr-xr-x   3 root root  4096 Dec 19 08:19 boot
    ...
    
    0 讨论(0)
  • 2020-12-02 11:19

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

    class 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 
    
    0 讨论(0)
  • 2020-12-02 11:25

    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.

    0 讨论(0)
  • 2020-12-02 11:34

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

       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')
    
    0 讨论(0)
提交回复
热议问题