从python中运行交互式命令

use*_*597 19 python stdin subprocess interactive stdout

我有一个脚本,我想在python(2.6.5)中运行,遵循以下逻辑:

  • 提示用户输入密码.看起来像("输入密码:")(*注意:输入不回显到屏幕)
  • 输出无关信息
  • 提示用户回复("Blah Blah filename.txt blah blah(Y/N)?:")

最后一个提示行包含我需要解析的文本(filename.txt).提供的响应无关紧要(只要我可以解析该行,程序实际上可以在不提供响应的情况下退出)

我的要求有点类似于在python脚本中包装交互式命令行应用程序,但是那里的响应看起来有点令人困惑,即使OP提到它不适合他,我仍然会挂起.

通过环顾四周,我得出的结论subprocess是这样做的最佳方式,但我遇到了一些问题.这是我的Popen系列:

p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
Run Code Online (Sandbox Code Playgroud)
  • 当我打电话给read()readline()打开时stdout,提示是打印机到屏幕并挂起.

  • 如果我叫write("password\n")stdin,提示被写入屏幕,它挂起.write()未写入文本(我没有光标移动新行).

  • 如果我调用p.communicate("password\n"),与write()相同的行为

我在这里寻找一些关于输入的最佳方式的想法,stdin如果你感觉很慷慨,可能如何解析输出中的最后一行,尽管我最终可能会想到这一点.

sid*_*rgt 12

如果您正在与子进程生成的程序进行通信,则应该检查python中subprocess.PIPE上的非阻塞读取.我的应用程序遇到了类似的问题,发现使用Queues是与子进程进行持续通信的最佳方式.

至于从用户获取值,您始终可以使用raw_input()内置来获取响应,对于密码,请尝试使用该getpass模块从用户获取非回显密码.然后,您可以解析这些响应并将它们写入子进程'stdin.

我最终做了类似于以下的事情:

import sys
import subprocess
from threading  import Thread

try:
    from Queue import Queue, Empty
except ImportError:
    from queue import Queue, Empty  # python 3.x


def 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 outStr

p = 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 = True
errThread.daemon = True

outThread.start()
errThread.start()

try:
    someInput = raw_input("Input: ")
except NameError:
    someInput = input("Input: ")

p.stdin.write(someInput)
errors = getOutput(errQueue)
output = getOutput(outQueue)
Run Code Online (Sandbox Code Playgroud)

完成队列并启动线程后,您可以循环获取用户的输入,获取进程的错误和输出,并处理并将其显示给用户.