Python subprocess - run multiple shell commands over SSH

61,930

basically if you call subprocess it creates a local subprocess not a remote one so you should interact with the ssh process. so something along this lines: but be aware that if you dynamically construct my directory it is suceptible of shell injection then END line should be a unique identifier To avoid the uniqueness of END line problem, an easiest way would be to use different ssh command

from __future__ import print_function,unicode_literals
import subprocess

sshProcess = subprocess.Popen(['ssh', 
                               <remote client>],
                               stdin=subprocess.PIPE, 
                               stdout = subprocess.PIPE,
                               universal_newlines=True,
                               bufsize=0)
sshProcess.stdin.write("ls .\n")
sshProcess.stdin.write("echo END\n")
sshProcess.stdin.write("uptime\n")
sshProcess.stdin.write("logout\n")
sshProcess.stdin.close()


for line in sshProcess.stdout:
    if line == "END\n":
        break
    print(line,end="")
Share:
61,930
user2978190
Author by

user2978190

Updated on July 09, 2022

Comments

  • user2978190
    user2978190 almost 2 years

    I am trying to open an SSH pipe from one Linux box to another, run a few shell commands, and then close the SSH.

    I don't have control over the packages on either box, so something like fabric or paramiko is out of the question.

    I have had luck using the following code to run one bash command, in this case "uptime", but am not sure how to issue one command after another. I'm expecting something like:

    sshProcess = subprocess.call('ssh ' + <remote client>, <subprocess stuff>)
    lsProcess = subprocess.call('ls', <subprocess stuff>)
    lsProcess.close()
    uptimeProcess = subprocess.call('uptime', <subprocess stuff>)
    uptimeProcess.close()
    sshProcess.close()
    

    What part of the subprocess module am I missing?

    Thanks

    pingtest = subprocess.call("ping -c 1 %s" % <remote client>,shell=True,stdout=open('/dev/null', 'w'),stderr=subprocess.STDOUT)
    if pingtest == 0:
      print '%s: is alive' % <remote client>
      # Uptime + CPU Load averages
      print 'Attempting to get uptime...'
      sshProcess = subprocess.Popen('ssh '+<remote client>, shell=True,stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
      sshProcess,stderr = sshProcess.communicate()
      print sshProcess
      uptime = subprocess.Popen('uptime', shell=True,stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
      uptimeProcess,stderr = uptimeProcess.communicate()
      uptimeProcess.close( )
      print 'Uptime         : ' + uptimeProcess.split('up ')[1].split(',')[0]
    else:
      print "%s: did not respond" % <remote client>
    
  • user2978190
    user2978190 over 10 years
    I was getting an error that stdin wasn't recognized, so I added the module name. Now it just hangs until I CTRL+C it. sshProcess = subprocess.Popen(['ssh', remoteClient],stdin=subprocess.PIPE, stdout = subprocess.PIPE) sshProcess.stdin.write('ls') sshProcess.stdin.write('echo END') for line in sshProcess.stdout.readlines(): if line == "END\n": break print(line) sshProcess.stdin.write("uptime") sshProcess.stdin.write("echo END") for line in sshProcess.stdout.readlines(): if line == "END\n": break print(line) Man this formatting is a pain in the butt.
  • Greg
    Greg almost 8 years
    sorry to be posting in an old question, but when I try this, I get IOError: File not open for reading on the line for line in stdout.readlines(): . I used from sys import stdout. I googled it but no luck. Any idea why this might be?
  • Xavier Combelle
    Xavier Combelle almost 8 years
    the stdout was the sshProcess one not sys one. Moreover I did test and everything did not work as expected. Now the example work
  • coradek
    coradek over 5 years
    granted this is old, but an alternative to the END trick is to use sshProcess.stdin.write("logout\n") as the final input. This closes the ssh connection and removes the need for the "if...break" when printing sshProcess.stdout