Skip to content

Instantly share code, notes, and snippets.

@bortzmeyer
Created October 13, 2011 13:42
Show Gist options
  • Save bortzmeyer/1284249 to your computer and use it in GitHub Desktop.
Save bortzmeyer/1284249 to your computer and use it in GitHub Desktop.
The only simple way to do SSH in Python today is to use subprocess + OpenSSH...
#!/usr/bin/python
# All SSH libraries for Python are junk (2011-10-13).
# Too low-level (libssh2), too buggy (paramiko), too complicated
# (both), too poor in features (no use of the agent, for instance)
# Here is the right solution today:
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
@colton22
Copy link

@taigrr use SSH keys; see ssh(1) and ssh-copy-id(1)

I agree with this... but what if we dont have keys? or the ability to use keys due to a corporate env and RSA revolving password?

@bkafi
Copy link

bkafi commented Dec 17, 2018

@girishlc
Try this version:

from __future__ import print_function
import os
import subprocess
import platform

PRIVATE_KEY_LOCATION = "C:/Users/johndoe/.ssh/id_rsa"
USER = "johndoe"
HOST = "192.168.1.1"
COMMAND="uname -a"
# Ports are handled in ~/.ssh/config since we use OpenSSH

system32 = os.path.join(os.environ['SystemRoot'], 'SysNative' if platform.architecture()[0] == '32bit' else 'System32')
ssh_path = os.path.join(system32, 'OpenSSH/ssh.exe')

ssh = subprocess.Popen([ssh_path, '-i', PRIVATE_KEY_LOCATION, "{}@{}".format(USER, HOST)],
                       stdin=subprocess.PIPE,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE)

std_data = ssh.communicate(COMMAND)

I ran into this problem as well.

See:
https://bugs.python.org/issue8557
https://stackoverflow.com/questions/41630224/python-does-not-find-system32

how does this convert over to Android file system?
Your script works perfectly from my kodi on windows and ssh's into a raspberry pi. I'm trying to get this working from an android Xiamoi Mi box. Any suggestions? :)

@johnnybubonic
Copy link

johnnybubonic commented Jan 30, 2019

this gist aged well. ELL OH ELL

edit: good luck with all your forked processes. i'm happy with paramiko.

@tarzan270786
Copy link

Hi All ,
I need a help . I am using below code as I want ssh to run few commands in bash mode . But I am getting errors .

import subprocess
import sys

HOST="root@192.168.1.2". # change the IP as per ur testing
COMMAND="ls / -ltrh"
print("Type ",type(COMMAND))
ssh = subprocess.Popen(["ssh", "%s" % HOST, "%s" %COMMAND],
shell=True,
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)

(venv) [rrshanke@slc10gon ADW]$ python ssh_try.py
('Type ', <type 'str'>)
ERROR: ['usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n', ' [-D [bind_address:]port] [-E log_file] [-e escape_char]\n', ' [-F configfile] [-I pkcs11] [-i identity_file]\n', ' [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n', ' [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n', ' [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n', ' [user@]hostname [command]\n']
(venv) [rrshanke@slc10gon ADW]$

I am not sure what is wrong . Please help me

@bortzmeyer
Copy link
Author

ssh = subprocess.Popen(["ssh", "%s" % HOST, "%s" %COMMAND],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)

You should read the documentation. https://docs.python.org/3/library/subprocess.html Executive summary: shell=True is both dangerous and a bad idea in most cases. From a Python program, shell=False is the right solution most of the time. (See in the doc, around "If shell is True, it is recommended to pass args as a string rather than as a sequence.")

@datlife
Copy link

datlife commented Nov 4, 2019

SSH without third-party library

Here is my take on SSH without using third-party library. I leveraged a concept of fork system call in UNIX [1].

# Create an ssh session with python
import os
import shlex

def create_ssh(host, user):
  """Create a ssh session"""
  ssh = "/usr/bin/ssh -t {user}@{host} ".format(user=user, host=host)
 
  # Now, fork a child from current process 
  # This is a basic concept from Operating System class.
  pid = os.fork()
  if pid == 0:  # a child process
     print("Executing: %s" %(ssh))
     cmd = shlex.split(ssh)
     os.execv(cmd[0], cmd)
  
  os.wait(pid, 0)
  print("ssh session is finished. :)")
 
if __name__ == "__main__":
  create_ssh(
      host="remote_host", 
      user="remote_user")

Ref:
[1] https://en.wikipedia.org/wiki/Fork_(system_call)

@Insektosaurus
Copy link

Insektosaurus commented Jan 11, 2020

Amazing

Still populating top three google results when searching for 'python3 connect ssh and run script' :)

@faddison
Copy link

faddison commented May 6, 2020

Still true today. Amazing how badly libraries like paramiko and fabric fail at such a simple task.

@rogercallster
Copy link

Still a valid chain but still finding it hard to reliably send password from Osx or linux

@hoon0912
Copy link

hoon0912 commented Jan 7, 2021

thank you

@HungPhann
Copy link

Can tell how amazing it is when this solution still works today.
Thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment