在 Python 内部运行交互式命令
- 2025-04-10 09:45:00
- admin 原创
- 21
问题描述:
我有一个脚本,想要在 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)
当我在 上调用
read()
或readline()
时stdout
,提示被打印到屏幕上并且挂起。如果我调用`write("password
")for
stdin,提示会写入屏幕并挂起。 中的文本
write()`不会写入(我不会将光标移到新行)。如果我调用`p.communicate("password
")`,行为与 write() 相同
如果您感觉慷慨的话,我在这里寻找一些关于输入的最佳方式stdin
以及如何解析输出中的最后一行的想法,尽管我最终可能会弄清楚这一点。
解决方案 1:
如果您正在与子进程生成的程序进行通信,则应检查Python 中对 subprocess.PIPE 的非阻塞读取。我的应用程序遇到了类似的问题,发现使用队列是与子进程进行持续通信的最佳方式。
至于从用户那里获取值,您始终可以使用内置的 raw_input() 来获取响应,对于密码,请尝试使用该getpass
模块从用户那里获取非回显密码。然后,您可以解析这些响应并将其写入子进程的标准输入。
我最终做了类似以下的事情:
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)
一旦创建了队列并启动了线程,您就可以循环获取来自用户的输入、从进程中获取错误和输出,然后处理并显示它们给用户。
解决方案 2:
对于简单的任务来说,使用线程可能有点过头了。相反,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
'.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
扫码咨询,免费领取项目管理大礼包!