我有一个脚本,我想在python(2.6.5)中运行,遵循以下逻辑:
最后一个提示行包含我需要解析的文本(filename.txt)。提供的响应无关紧要(只要我能解析该行,该程序实际上可以在不提供响应的情况下退出)
我的要求有些类似于Wrapping an interactive command line application in a python script,但那里的回答似乎有些令人困惑,即使OP提到它不适合他,我仍然会挂起。
通过环顾四周,我得出的结论是subprocess
是最好的方法,但我遇到了一些问题。这是我的Popen系列:
p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
当我在read()
上拨打readline()
或stdout
时,系统会在屏幕上显示提示符并挂起。
如果我为write("password\n")
调用stdin
,则会将提示写入屏幕并挂起。 write()
中的文字未写入(我没有光标移动新行)。
如果我调用p.communicate("password\n")
,则行为与write()
我在这里寻找一些关于输入stdin
的最佳方式的想法,如果你感觉很慷慨,可能如何解析输出中的最后一行,尽管我最终可能会想到这一点。
答案 0 :(得分:11)
如果您正在与子进程生成的程序进行通信,则应该查看Non-blocking read on a subprocess.PIPE in python。我的应用程序遇到了类似的问题,发现使用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)
创建队列并启动线程后,您可以循环获取用户的输入,获取进程的错误和输出,并处理并将其显示给用户。
答案 1 :(得分:0)
使用线程对于简单的任务来说可能有些过分。 而是可以使用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