2

I've created an expect script that, when executed, ssh's onto a server and executes a series of commands. Pseudocode looks like this:

#!/usr/bin/expect spawn ssh usr@myip expect "password:" send "mypassword\n"; send "./mycommand1\r" send "./mycommand2\r" interact 

When executed from a bash shell ($ ./myscript.txt) the code executes fine. What I would now like to do is have a line in python file that runs the commands in the script the same way the bash shell does. Pseudocode looks like this:

import subprocess def runmyscript(): subprocess.call("myscript.txt", executable="expect", shell=True) def main(): run = runmyscript(): if __name__ == '__main__': main() 

I have placed the myscript.txt script file in the same directory as my runmyscript.py file, yet when I run the python file I receive the error:

WindowsError: [Error 2] The system cannot find the file specified 

I've read through the documentation on the python.org site, but to no avail. Does anyone have a cunning solution for executing bash scripts from within .py code?

SOLUTION: this code works for me.

child = subprocess.Popen(['bash', '-c', './myscript.txt'], stdout = subprocess.PIPE) 

Used this code to call an Expect file to ssh and send commands to server from .py file - useful solution if you are having trouble getting pycrypto/paramiko built onto your machine.

8
  • 1
    Well, you could run /usr/bin/expect myscript.txt, but you could also write the whole expect script in python (which I'd recommend) Commented Jun 21, 2012 at 22:15
  • 1
    See also stackoverflow.com/questions/1233655/… Commented Jun 21, 2012 at 22:17
  • lkjoel - how would I rewrite my command lines in myscript.txt from python? Writing the expect script in python would be certainly be preferable - would make it easier to add commands. user946850's link is useful for the ssh section. Commented Jun 21, 2012 at 22:24
  • For that matter, what python command could 'run /usr/bin/expect myscript.txt'? Thanks for all of your help. Commented Jun 21, 2012 at 22:26
  • @gortron - you could write it in python using the pexepect module. Even better would be to use paramiko in your case. Also, that script is not bash at all. Commented Jun 21, 2012 at 22:30

2 Answers 2

3

Here is a python implementation of your expect script:

import paramiko user = "user" pass = "pass" host = "host" client = paramiko.SSHClient() client.load_system_host_keys() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(host, port=22, username=user, password=pass) client.exec_command("./mycommand1") client.exec_command("./mycommand2") client.close() 
Sign up to request clarification or add additional context in comments.

1 Comment

Paramiko has proven very difficult to install on my Python build. I'll keep striving for the subprocess solution and post it here when I find it.
1

You can use pexpect (http://www.noah.org/wiki/pexpect)

Here is an example function that handles quite a few cases you can run into when executing commands remotely over ssh.

import pexpect ## Cleanly handle a variety of scenarios that can occur when ssh or scp-ing to an ip:port # amongst them are: # # (1) key has not been setup # (2) key has changed since last time # (3) command was executed (check exit status and output) # # @param cmdLine The "scp" or "ssh" command-line # @param mtimeout The millisecond timeout to wait for the child process to return # @param log The log to record events to if necessary def cleanlyHandleSecureCmd(cmdLine, mtimeout = None, log = None): status = -1 output = None if mtimeout == None: mtimeout = 60 * 1000 if cmdLine != None and ('scp' in cmdLine or 'ssh' in cmdLine): # Scenarios for ssh include: (1) key not setup (2) key changed (3) remote cmd was executed (check exit status) scenarios = ['Are you sure you want to continue connecting', '@@@@@@@@@@@@', EOF] child = spawn(cmdLine, timeout = mtimeout) scenario = child.expect(scenarios) if scenario == 0: # (1) key not setup ==> say 'yes' and allow child process to continue child.sendline('yes') scenario = child.expect(scenarios) if scenario == 1: if log != None: # (2) key changed ==> warn the user in the log that this was encountered log.write('WARNING (' + cmdLine + '): ssh command encountered man-in-the-middle scenario! Please investigate.') lines = child.readlines() scenario = child.expect([EOF]) child.close() else: # (3) remote cmd was executed ==> check the exit status and log any errors child.close() status = child.exitstatus output = child.before output = sub('\r\n', '\n', output) # Do not be pedantic about end-of-line chars output = sub('\n$', '', output) # Ignore any trailing newline that is present if status == None: status = child.status if status != 0 and log != None: log.error('Error executing command \'' + str(cmdLine) + '\' gave status of ' + str(status) + ' and output: ' + str(output)) else: if log != None: log.error('Command-line must contain either ssh or scp: ' + str(cmdLine)) return (status, output) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.