Python: Respond to Command Line Prompts Python: Respond to Command Line Prompts python python

Python: Respond to Command Line Prompts


In the comments you mentioned that xx viewproject < answers.txt > output.txt works but you can't use it because answers depend on the output from the subprocess.

In general pexpect-like modules such as winpexpect (for Windows) could be used. Something like:

import reimport sysfrom functools import partialfrom winpexpect import EOF, winspawn as spawnp = spawn('xx viewproject')p.logfile = sys.stdoutpatterns = ['the project:', re.escape('? [ynYN](n)'), EOF]for found in iter(partial(p.expect, patterns), 2): # until EOF    if found == 0:        p.sendline(project_name)    elif found == 1:        filename = get_filename_from_prompt(p.before) # a regex could be used        answer = yes_or_no_from_subproject.get(filename, 'no') # a dict        p.sendline(answer)

If the prompts are terminated with a newline (and the subprocess doesn't buffer them); you could read line by line using subprocess module directly:

from subprocess import Popen, PIPEwith Popen(["xx", "viewproject"], stdin=PIPE, stdout=PIPE,            universal_newlines=True) as p:    for line in p.stdout:         if line.startswith("Please enter the name of the project"):            answer = project_name        elif line.startswith("Would you like to recurse into the subproject"):            filename = get_filename_from_prompt(line) # a regex could be used            answer = yes_or_no_from_subproject.get(filename, 'n') # a dict        else:            continue # skip it        print(answer, file=p.stdin) # provide answer        p.stdin.flush()

To test that you can read something from the xx using subprocess:

from subprocess import Popen, PIPE, STDOUTwith Popen(["xx", "viewproject"], bufsize=0,           stdin=PIPE, stdout=PIPE, stderr=STDOUT) as p:    print(repr(p.stdout.read(1)))


Yes, first of all you may create subprocess as an object by:

p = subprocess.Popen('xx viewproject', shell=True, stdin=subprocess.PIPE,                       stdout=subprocess.PIPE, universal_newlines=True)

Then you'll have methods like communicate() available, for instance:

newline = os.linesep # [1]commands = ['y', 'n', 'y', 'n', 'y']p.communicate( newline.join( commands))

1 - os.linesep

Which will send all the answers at once (and hopefully it'll be enough) relying on the same order of question every time.

You may also try parsing p.stdout and then writing to p.stdin, but this may cause deadlock when one buffer will get full while waiting for another, so be careful with this. Luckily there are some complex examples on google.

Simple version would be:

p = Popen(...)line = p.stdout.readline() # At this point, if child process will wait for stdin                           # you have a deadlock on your handsparse_line( line)p.stdin.write( newline.join( commands).encode( 'utf-8'))

I would also consider rewriting:

p = subprocess.Popen('si viewproject --project=d:/Projects/test.pj', shell=True,                       stdin=subprocess.PIPE, stdout=subprocess.PIPE) 

To:

p = subprocess.Popen( ['si', 'viewproject', '--project=d:/Projects/test.pj'],                      shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

Unless you explicitly need Shell invocation.