By fredley


2010-08-27 16:09:01 8 Comments

I'm writing a script to automate some command line commands in Python. At the moment I'm doing calls thus:

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

However I need to run some commands on a remote machine. Manually, I would log in using ssh and then run the commands. How would I automate this in Python? I need to log in with a (known) password to the remote machine, so I can't just use cmd = ssh [email protected], I'm wondering if there's a module I should be using?

13 comments

@Pedro Lobito 2020-06-15 16:04:28

The accepted answer didn't work for me, here's what I used instead:

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
...

Alternatively, you can use sshpass:

import subprocess
cmd = """ sshpass -p "myPas$" ssh [email protected] -p 22222 'my command; exit' """
print( subprocess.getoutput(cmd) )

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

@Ronn Macc 2019-08-10 05:49:06

Keep it simple. No libraries required.

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()

@Ronn Macc 2020-01-31 14:47:39

Subprocess is your swiss army knife in automation. You can then combine Python with endless possibilities like shell scripts, sed, awk, grep. Yes you can all do in Python, but wouldnt it be great to just run a grep somewhere in python - well you can.

@BeingSuman 2020-02-06 11:09:11

if your ssh commands asks for password how would you provide that in Python file ?

@mmrbulbul 2020-05-15 07:47:02

@BeingSuman You can use SSH key authentication for that. Though I guess You already have figured that out.

@Harshan Gowda 2019-05-11 08:34:15

Works Perfectly...

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()

@Harshan Gowda 2019-05-14 10:21:24

#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)

@Harshan Gowda 2019-05-13 16:26:21

Below example, incase if you want user inputs for hostname,username,password and port no.

  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()

@snakecharmerb 2019-05-13 16:45:29

Rather than reposting your answer from two days ago with better formatting, why not edit the older answer and improve its formatting?

@Harshan Gowda 2019-05-14 10:27:04

Asking User to enter the command as per the device they are logging in.
The below code is validated by 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)

@Alexander Tereshkov 2019-01-15 23:42:03

paramiko finally worked for me after adding additional line, which is really important one (line 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)

Make sure that paramiko package is installed. Original source of the solution: Source

@marko.ristin 2018-05-16 03:28:53

Have a look at spurplus, a wrapper we developed around spur that provides type annotations and some minor gimmicks (reconnecting SFTP, md5 etc.): https://pypi.org/project/spurplus/

@Alex R 2019-06-27 12:24:57

a wrapper around a wrapper around a wrapper .. nice :)

@marko.ristin 2019-06-28 13:09:32

Well, if you want to keep your deployment scripts trivial, I doubt that the underlying tools are simple/abstract enough. So far, we didn't observe leaky abstractions.

@IAmSurajBobade 2017-03-28 13:32:39

All have already stated (recommended) using paramiko and I am just sharing a python code (API one may say) that will allow you to execute multiple commands in one go.

to execute commands on different node use : Commands().run_cmd(host_ip, list_of_commands)

You will see one TODO, which I have kept to stop the execution if any of the commands fails to execute, I don't know how to do it. please share your knowledge

#!/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:])

Thank you!

@shahjapan 2010-08-27 16:18:03

I will refer you to paramiko

see this question

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

@user239558 2015-02-24 09:09:22

The assumption here is that paramiko is as secure as (open)ssh. Is it?

@Ardit 2016-05-09 10:24:18

what if the ssh-keys are exchanged?

@alfonso 2016-09-14 19:23:15

@R-Dit, for ssh keys, try getting rid of the password parameter and run the following command before connecting: ssh.load_system_host_keys().

@Scott Prive 2017-04-20 14:21:27

If you're using SSH keys, first prepare the keyfile using 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()) and finally ssh..connect(hostname=host, username=user, pkey=k).

@Scott Prive 2017-04-20 14:27:31

As a long-time user of Paramiko (but not an expert), I can suggest using Paramiko but you should consider your use cases and how much you're willing to learn. Paramiko is very low-level, and you can easily fall into a trap where you create a "command running helper function" without fully understanding the code you're using. That means you might design say a def run_cmd(host, cmd): which does what you want at first, but your needs evolve. You end up changing the helper for the new use case, which changes behavior of the older existing usage. Plan accordingly.

@Scott Prive 2017-04-20 14:29:25

There is also this list of SSH wrappers in the Python wiki: wiki.python.org/moin/SecureShell It is a little out of date, as it omits python-executor (pypi.python.org/pypi/executor)

@Nemo 2019-01-22 08:16:25

For unknown host error, do: ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) before

@Ronn Macc 2019-08-10 05:51:04

whats wrong with ssh ?... User subprocess to invoke. See answer below.

@powerrox 2010-08-27 16:44:46

Or you can just use commands.getstatusoutput:

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

I used it extensively and it works great.

In Python 2.6+, use subprocess.check_output.

@Philip Kearns 2013-11-26 09:26:11

+1 for a nice simple built-in method. In my current setup I do not want to be adding Python libraries so your suggestion is valuable, very straightforward too.

@powerrox 2014-06-17 21:12:13

just make sure your remote host is setup for passwordless ssh, if not, you have to do other things for managing authentication

@Tim S. 2015-09-08 21:52:07

subprocess.check_output -- great solution!

@ealeon 2015-11-30 05:45:24

@powerrox what are those "other things?"

@powerrox 2015-12-01 16:22:57

@TimS. you may have to include handling for authentication by whatever means is appropriate for your setup. I used expect to enter password at the prompt. then there is this thread with other solutions: unix.stackexchange.com/questions/147329/…

@Michael Williamson 2013-01-10 21:37:06

I found paramiko to be a bit too low-level, and Fabric not especially well-suited to being used as a library, so I put together my own library called spur that uses paramiko to implement a slightly nicer interface:

import spur

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

If you need to run inside a shell:

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

@davidlt 2013-02-07 13:55:33

I decided to try spur. You generate additional shell commands and you end up with: which 'mkdir' > /dev/null 2>&1 ; echo $?; exec 'mkdir' '-p' '/data/rpmupdate/20130207142923'. I would like to have also access to a plain exec_command. Also missing ability to run background tasks: nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &. E.g., I generate a zsh script (rpmbuildpackages) using template and then I just to leave it running on the machine. Maybe ability to monitor such background jobs also would be nice (saving PIDs in some ~/.spur).

@Gabriel 2013-06-05 01:25:18

spur apparently only works on unix systems cause it has a dependency on termios. Does anybody know a good library for Windows?

@ravemir 2014-03-12 16:58:03

Not entirely true: if you use a precompiled installer, you will be able to install paramiko and spur. I just did it myself...

@Michael Williamson 2014-08-25 14:02:59

@Gabriel: one of the recent releases should have improved support on Windows. If it's still not working, please feel free to open an issue.

@Michael Williamson 2014-08-25 14:04:14

@davidlt: when constructing an SshShell, there is now the option to set the shell type. If a minimal shell is used by passing in shell_type=spur.ssh.ShellTypes.minimal, then only the raw command is sent. Implementing background tasks directly feels a bit out of scope for Spur, but you should be able to run the command you've described by invoking a shell e.g. shell.run(["sh", "-c", "nohup ./bin/rpmbuildpackages < /dev/null >& /dev/null &"]).

@Eric Snow 2010-08-27 17:25:11

I have used paramiko a bunch (nice) and pxssh (also nice). I would recommend either. They work a little differently but have a relatively large overlap in usage.

@Oben Sonne 2014-02-03 19:48:42

The link to pxssh is a nice journey back in time.

Related Questions

Sponsored Content

47 Answered Questions

62 Answered Questions

[SOLVED] How to call an external command?

12 Answered Questions

[SOLVED] Iterating over dictionaries using 'for' loops

42 Answered Questions

[SOLVED] How to get the current time in Python

  • 2009-01-06 04:54:23
  • user46646
  • 3437040 View
  • 3047 Score
  • 42 Answer
  • Tags:   python datetime time

27 Answered Questions

[SOLVED] ssh "permissions are too open" error

  • 2012-02-14 02:02:31
  • Yannick Schall
  • 1504733 View
  • 2184 Score
  • 27 Answer
  • Tags:   permissions ssh

22 Answered Questions

[SOLVED] What are metaclasses in Python?

16 Answered Questions

[SOLVED] Getting ssh to execute a command in the background on target machine

  • 2008-08-26 22:55:58
  • dagorym
  • 301887 View
  • 313 Score
  • 16 Answer
  • Tags:   bash ssh csh

10 Answered Questions

[SOLVED] Does Python have a string 'contains' substring method?

17 Answered Questions

[SOLVED] How to use SSH to run a local shell script on a remote machine?

26 Answered Questions

[SOLVED] Does Python have a ternary conditional operator?

Sponsored Content