1

I have a little test.sh script that I run from the command line ./test.sh and it will ask me for input to 2 questions that I enter, then it loops till I ctrl-c out of it.

I want to write a little python script that can run my test.sh, and enter the inputs to the script questions from variables, var1 and var2 that I set in python.

I also want to have another variable, var3, that loops for x long and runs my test.sh, and ends it then relaunches it every x minutes based on the value of var3

I wrote this code but it doesn't seem to pass the commands into my test.sh after it launches:

import os
os.system('./test.sh arg1')
time.sleep(10)
sh('input answer 1')
time.sleep(5)
sh('input answer 2')

Currently my code has been updated based on this thread to look like this:

#!/usr/bin/env python

import pexpect
import sys
import os
child = pexpect.spawn ('./test.sh -arg1')
child.expect ('some expected output from the .sh file')
child.expect ('more expected output from the .sh file')
child.expect ('(?i)Enter Username:')
child.sendline ('myusername')
child.expect ('(?i)Enter Password:')
child.sendline ('mypassword')
# sys.stdout.write (child.after)
# sys.stdout.flush()
time.sleep(30)
child.sendcontrol('c')
child.close()
print 'Goodbye'

--fixed-- Now the problem is my timeout or sleep is getting inturrupted, possibly by my .sh script's output. When I run this script with either timeout or time.sleep uncommented, it either has no affect and goes straight down the line to my child.close() and ends the program, or it hangs up the child.sendline ('mypassword') for some reason and I get stuck at my .sh script's password prompt... maybe it's not really stuck there because I can't interact with it. --fixed--

Once I get the script pausing for 30 seconds (or x) then all I will have left to do is make the whole thing loop x times. Finnaly I'll need to add error checking because the .SH responds with different strings of text that can indicate I need to run the script again right away.

Thanks for everyone's help so much!

Node TX
  • 175
  • 1
  • 10
  • 3
    Read http://docs.python.org/3/library/subprocess.html notably about `popen` – Basile Starynkevitch Dec 24 '12 at 19:17
  • 1
    What does *"then it loops"* mean: it asks you 2 questions again or new input is not expected after the initial 2 questions? What does *"loops for x long"* mean: for `x` seconds or `x` times? – jfs Dec 24 '12 at 19:40
  • 2
    Is there some reason you don't want to do this in Python? – Tyler Crompton Dec 24 '12 at 19:51
  • I just fixed the above code so that it now works! The problem with the time.sleep not working was the output I was streaming in from my sys.stdout.write (child.after) and/or sys.stdout.flush() statement. I commented the lines and now it works!!! – Node TX Dec 27 '12 at 14:27

2 Answers2

2

Using pexpect:

import pexpect  # $ pip install pexpect

while var3:  # start ./test.sh again
    output = pexpect.run('./test.sh arg1', 
        timeout=x,  # terminate child process after x seconds
        events={r'(?i)question 1': var1,  # provide answers
                r'(?i)question 2': var2})  

Note: subprocess-based solution might be more complex due to buffering issues and it might require additionally pty, select modules, example.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • pexpect worked for me. I wrote it a little different though, and it runs ok, but seems to crash out after a minute I'm looking into why. I used this code: import pexpect x = 1 var3 = True var1 = 'mytext' var2 = 'myothertext' while var3: child = pexpect.spawn ('./test.sh -arg1') child.expect ('output from my test.sh...') child.expect ('') child.expect ('var1 input entry') child.sendline ('var1') child.expect ('var2 input entry') child.sendline ('var2') – Node TX Dec 26 '12 at 05:34
  • @NodeTX: don't put the code into the comment; [update your question](http://stackoverflow.com/posts/14024957/edit) instead. If you use `spawn()` instead of `run()` then you should handle TIMEOUT, EOF conditions and call `child.close()` yourself. Also you might want `.sendline(var1)` instead of `.sendline("var1")`. And `.expect("")` might be useless (empty string matches any input). `run()` is enough in your case. – jfs Dec 26 '12 at 07:18
  • Thanks J.F Sebastian I was wondering why my code block wouldn't show up in the comment, that explains why! – Node TX Dec 27 '12 at 13:45
1
import subprocess
p = subprocess.Popen('./test.sh arg1', stdin=subprocess.PIPE, stdout=subprocess.PIPE)

time.sleep(10)
p.stdin.write('input answer 1') #Probably adding \n is necessary
time.sleep(5)
p.stdin.write('input answer 2') #Probably adding \n is necessary

print p.stdout.readline() # To print one-line output of the shell script
MostafaR
  • 3,547
  • 1
  • 17
  • 24
  • I think you mean `p.stdout.readline()` and `p.stdin.write()` ? – jdi Dec 24 '12 at 19:58
  • There is no `popen`. It should be `Popen`. Also, see [Q: Why not just use a pipe (popen())?](http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F). In addition your code might dead-lock if `./test.sh` generates enough output (see appropriate warning in `subprocess` docs). – jfs Dec 24 '12 at 20:07
  • @jdi, Thank you very much, these are errors of typing answer in Stackoverflow's editor :) – MostafaR Dec 24 '12 at 20:10
  • @J.F.Sebastian Thank you very much, yes It's not a perfect solution, but I think sometimes we need easy and quick solutions. – MostafaR Dec 24 '12 at 20:11
  • `p.stdout.readline()` will block forever if `./tesh.sh` uses block-buffering for its output (default if stdout is a pipe). The reasons are explained [in the link I've provided](http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F). – jfs Dec 24 '12 at 20:27