Running an interactive command from within Python Running an interactive command from within Python python python

Running an interactive command from within Python


If you are communicating with a program that subprocess spawns, you should check out A non-blocking read on a subprocess.PIPE in Python. I had a similar problem with my application and found using queues to be the best way to do ongoing communication with a subprocess.

As for getting values from the user, you can always use the raw_input() builtin to get responses, and for passwords, try using the getpass module to get non-echoing passwords from your user. You can then parse those responses and write them to your subprocess' stdin.

I ended up doing something akin to the following:

import sysimport subprocessfrom threading import Threadtry:    from Queue import Queue, Emptyexcept ImportError:    from queue import Queue, Empty  # Python 3.xdef enqueue_output(out, queue):    for line in iter(out.readline, b''):        queue.put(line)    out.close()def getOutput(outQueue):    outStr = ''    try:        while True: # Adds output from the Queue until it is empty            outStr+=outQueue.get_nowait()    except Empty:        return outStrp = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True)outQueue = Queue()errQueue = Queue()outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue))errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue))outThread.daemon = TrueerrThread.daemon = TrueoutThread.start()errThread.start()try:    someInput = raw_input("Input: ")except NameError:    someInput = input("Input: ")p.stdin.write(someInput)errors = getOutput(errQueue)output = getOutput(outQueue)

Once you have the queues made and the threads started, you can loop through getting input from the user, getting errors and output from the process, and processing and displaying them to the user.


Using threading it might be slightly overkill for simple tasks.Instead os.spawnvpe can be used. It will spawn script shell as a process. You will be able to communicate interactively with the script. In this example I passed password as an argument, obviously it is a not good idea.

import osimport sysfrom getpass import unix_getpassdef cmd(cmd):    cmd = cmd.split()    code = os.spawnvpe(os.P_WAIT, cmd[0], cmd, os.environ)    if code == 127:        sys.stderr.write('{0}: command not found\n'.format(cmd[0]))    return codepassword = unix_getpass('Password: ')cmd_run = './run.sh --password {0}'.format(password)cmd(cmd_run)pattern = raw_input('Pattern: ')lines = []with open('filename.txt', 'r') as fd:    for line in fd:        if pattern in line:            lines.append(line)# manipulate lines