在Python中运行一个交互命令

我有一个脚本,我想要从Python(2.6.5),遵循以下逻辑运行:

  • 提示用户input密码。 看起来像(“input密码:”)(*注:input不回显屏幕)
  • 输出不相关的信息
  • 提示用户回复(“Blah Blah filename.txt等等等等(是/否)?:”)

最后的提示行包含我需要parsing的文本(filename.txt)。 提供的响应无关紧要(只要我可以parsing该行,程序实际上可以退出而不提供任何一个)

我的要求有点类似于在python脚本中包装交互式命令行应用程序 。 也许我只是有点厚,但是在那里的回答看起来有点混乱,即使在OP提到它不适合他的时候,我仍然会挂断。

通过环视,我得出这样的结论,即subprocess是做这件事的最好方式,但是我有一些问题。 打印线在下面

p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) 
  • 当我在标准输出上调用read()或readline()时,提示符是打印机到屏幕,并挂起。

  • 如果我为stdin调用write(“password \ n”),提示将被写入屏幕并挂起。 write()中的文本没有被写入(我没有移动光标移动一个新行)。

  • 如果我调用p.communicate(“password \ n”),则与write()

我在这里寻找了一些关于input到stdin的最佳方法,如果你觉得慷慨的话,如何parsing输出中的最后一行,尽pipe我最终可能会弄清楚。 谢谢!

如果你正在与一个subprocess产生的程序进行通信,你应该检查一下python中的subprocess.PIPE的非阻塞读取 。 我和我的应用程序有类似的问题,并发现使用队列是与subprocess进行持续通信的最佳方式。

至于从用户那里获取值,你总是可以使用raw_input()内build来获得响应,对于密码,可以尝试使用getpass模块来获取用户的非回显密码。 然后你可以parsing这些响应并把它们写到你的subprocess的标准input。

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

 import Queue import threading import subprocess 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 Queue.Empty: return outStr p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stout=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() someInput = raw_input("Input: ") p.stdin.write(someInput) errors = getOutput(errQueue) output = getOutput(outQueue) 

一旦你有了队列和线程的启动,你可以通过从用户获取input,获取错误和输出进程,并处理并显示给用户。

使用线程对于简单的任务可能稍微矫枉过正。 相反,可以使用os.spawnvpe。 它会产生一个脚本shell作为一个进程。 您将能够与脚本进行交互式通信。 在这个例子中,我通过密码作为参数,显然这是一个不好的主意。

 import os import sys from getpass import unix_getpass def 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 code password = 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