Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
@josephcoombe
Copy link

josephcoombe commented Sep 20, 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

@jmp8600
Copy link

jmp8600 commented Oct 2, 2018

i am using py script like below:

import subprocess
import sys

HOST="root@192.168.1.25"
COMMAND="ls / -ltrh"

ssh = subprocess.Popen(["ssh", "%s" % HOST, 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)

the print command prints output but evenything is inside bracket and bunch on newline,tabs and other characters...How do i properly format this output? I tried result.decode('utf-8') but i get an error that decode is not available...any idea?

[b'total 20K\n', b'drwxr-xr-x. 2 root root 6 Apr 11 00:59 srv\n', b'drwxr-xr-x. 2 root root 6 Apr 11 00:59 mnt\n', b'drwxr-xr-x. 2 root
root 6 Apr 11 00:59 media\n', b'drwxr-xr-x. 2 root root 6 Apr 11 00:59 home\n', b'lrwxrwxrwx. 1 root root 7 Sep 26 18:18 bin -> usr/b
in\n', b'lrwxrwxrwx. 1 root root 9 Sep 26 18:18 lib64 -> usr/lib64\n', b'lrwxrwxrwx. 1 root root 7 Sep 26 18:18 lib -> usr/lib\n', b'lrwx
rwxrwx. 1 root root 8 Sep 26 18:18 sbin -> usr/sbin\n', b'drwxr-xr-x. 13 root root 155 Sep 26 18:18 usr\n', b'dr-xr-xr-x. 5 root root 4.0K
Sep 26 18:26 boot\n', b'drwxr-xr-x. 19 root root 267 Sep 26 22:26 var\n', b'drwxr-xr-x. 3 root root 16 Sep 27 20:26 opt\n', b'dr-xr-xr-x. 11
0 root root 0 Sep 29 04:08 proc\n', b'dr-xr-xr-x. 13 root root 0 Sep 29 04:08 sys\n', b'drwxr-xr-x. 19 root root 3.1K Sep 29 18:22 dev\n',
b'drwxr-xr-x. 24 root root 740 Sep 30 05:22 run\n', b'drwxr-xr-x. 79 root root 8.0K Sep 30 05:22 etc\n', b'drwxrwxrwt. 9 root root 4.0K Sep 30
07:19 tmp\n', b'dr-xr-x---. 3 root root 170 Sep 30 07:21 root\n']

@colton22
Copy link

colton22 commented Nov 27, 2018

@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

tarzan270786 commented Aug 12, 2019

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

bortzmeyer commented Aug 12, 2019

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

rogercallster commented Jun 7, 2020

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

HungPhann commented Jan 18, 2021

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