使用Python的交互式输入/输出
我有一个与用户交互的程序(就像一个shell),我想使用Python子流程模块以交互方式运行它。 这意味着,我希望能够写入标准输入,并立即从标准输出中获取输出。我尝试了这里提供的许多解决方案,但似乎没有一个能满足我的需要 我写的代码是基于 问题是队列仍然是空的,就好像没有输出一样。 只有当我将程序需要执行和终止的所有输入写入标准输入时,我才能得到输出(这不是我想要的)。例如,如果我做了如下操作:使用Python的交互式输入/输出,python,subprocess,stdout,stdin,interactive,Python,Subprocess,Stdout,Stdin,Interactive,我有一个与用户交互的程序(就像一个shell),我想使用Python子流程模块以交互方式运行它。 这意味着,我希望能够写入标准输入,并立即从标准输出中获取输出。我尝试了这里提供的许多解决方案,但似乎没有一个能满足我的需要 我写的代码是基于 问题是队列仍然是空的,就好像没有输出一样。 只有当我将程序需要执行和终止的所有输入写入标准输入时,我才能得到输出(这不是我想要的)。例如,如果我做了如下操作: p.stdin.write("1\n5\n") errors = getOutp
p.stdin.write("1\n5\n")
errors = getOutput(errQueue)
output = getOutput(outQueue)
有没有办法做我想做的事
该脚本将在Linux机器上运行。我更改了脚本并删除了universal_newlines=True+将bufsize设置为1,并在写入后立即刷新标准输入。我仍然没有得到任何输出 第二次尝试: 我尝试了这个解决方案,它对我有效:
from subprocess import Popen, PIPE
fw = open("tmpout", "wb")
fr = open("tmpout", "r")
p = Popen("./a.out", stdin = PIPE, stdout = fw, stderr = fw, bufsize = 1)
p.stdin.write("1\n")
out = fr.read()
p.stdin.write("5\n")
out = fr.read()
fw.close()
fr.close()
Linux上此问题的两种解决方案: 第一种方法是使用文件写入输出,同时从中读取输出:
from subprocess import Popen, PIPE
fw = open("tmpout", "wb")
fr = open("tmpout", "r")
p = Popen("./a.out", stdin = PIPE, stdout = fw, stderr = fw, bufsize = 1)
p.stdin.write("1\n")
out = fr.read()
p.stdin.write("5\n")
out = fr.read()
fw.close()
fr.close()
第二,正如J.F.Sebastian提供的,使用fnctl模块使p.stdout和p.stderr管道不堵塞:
import os
import fcntl
from subprocess import Popen, PIPE
def setNonBlocking(fd):
"""
Set the file description of the given file descriptor to non-blocking.
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
p = Popen("./a.out", stdin = PIPE, stdout = PIPE, stderr = PIPE, bufsize = 1)
setNonBlocking(p.stdout)
setNonBlocking(p.stderr)
p.stdin.write("1\n")
while True:
try:
out1 = p.stdout.read()
except IOError:
continue
else:
break
out1 = p.stdout.read()
p.stdin.write("5\n")
while True:
try:
out2 = p.stdout.read()
except IOError:
continue
else:
break
目前的答案都不适合我。最后,我让它工作起来:
import subprocess
def start(executable_file):
return subprocess.Popen(
executable_file,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
def read(process):
return process.stdout.readline().decode("utf-8").strip()
def write(process, message):
process.stdin.write(f"{message.strip()}\n".encode("utf-8"))
process.stdin.flush()
def terminate(process):
process.stdin.close()
process.terminate()
process.wait(timeout=0.2)
process = start("./dummy.py")
write(process, "hello dummy")
print(read(process))
terminate(process)
使用此dummy.py
脚本进行测试:
#!/usr/bin/env python3.6
import random
import time
while True:
message = input()
time.sleep(random.uniform(0.1, 1.0)) # simulates process time
print(message[::-1])
注意事项是:输入/输出总是使用换行符,每次写入后刷新子级的stdin,并使用子级stdout中的readline()
(所有这些都在函数中管理)
在我看来,这是一个非常简单的解决方案(不是我的,我在这里找到的:)。我使用的是Python 3.6。这里是一个交互式shell。您必须在单独的线程上运行read(),否则它将阻止write()
据我所知,最简单的方法是在两侧创建专用线程:两个用于父进程上的stdout/stderr,一个用于子进程上的stdin。请找出这类例子的一部分。我不太明白你的意思。首先我想做的是只读取部分输出(一行),我不理解您的示例。这一行:p=Popen([sys.executable,“-u”,“-c”表示iter中的行(输入:”):print(“a”*int(line)*10**6)”),stdin=PIPE,stdout=PIPE,bufsize=1)是什么意思?没错,我在使用第二个解决方案时对其进行了编辑。问题是,当我开始尝试解决方案时,我已经在python解释器上尝试过了(我没有编写脚本,只是手动测试),所以它可以工作(因为人类的响应时间很慢)。当我尝试编写脚本时,遇到了您提到的问题,因此我添加了while循环,直到输入准备就绪。我实际上得到了整个输出,或者什么都没有(IOError异常),如果我上传a.out源代码(这是一个C程序)会有帮助吗?不幸的是,我想要与之通信的脚本使用了
stty-echo
,这导致它在尝试使用第一种方法时抱怨“标准输入”:设备的ioctl不正确。(第二种方法似乎永远无法正确读取输出..假设脚本正在输出)第二种解决方案永远挂起,当调用一个简单的C程序,请求使用scanf(“%s”,buf)进行2次输入时。好的,代码不会显示在赏金中,所以我做了一个要点,我只是想在后台用一个真正的python进程来测试它。你看了这个吗:?相关:如果有人想在现代python中这样做,我在这里发布了一个明确的答案:谢谢!我通过改变两行代码使它在Windows上工作:p=Popen('/bin/bash',stdin=PIPE…
到p=Popen(['cmd.exe',stdin=PIPE…
和linedata=p.stdout.read(1).解码(“utf-8”)
到data=p.stdout.read(1).解码(“cp437”)
。如果有人想在Windows上运行它,那就好了。您的答案是最好的!谢谢!stdin.flush()
这是一个巧妙的技巧!谢谢!我只想评论一下,我已经尝试了45分钟来完成这项看似非常简单的任务,结果证明stdin.flush是解决所有问题的解决方案。我还没有在我读过的任何其他答案中看到这一行。
#!/usr/bin/env python3.6
import random
import time
while True:
message = input()
time.sleep(random.uniform(0.1, 1.0)) # simulates process time
print(message[::-1])
import sys
import os
import subprocess
from subprocess import Popen, PIPE
import threading
class LocalShell(object):
def __init__(self):
pass
def run(self):
env = os.environ.copy()
p = Popen('/bin/bash', stdin=PIPE, stdout=PIPE, stderr=subprocess.STDOUT, shell=True, env=env)
sys.stdout.write("Started Local Terminal...\r\n\r\n")
def writeall(p):
while True:
# print("read data: ")
data = p.stdout.read(1).decode("utf-8")
if not data:
break
sys.stdout.write(data)
sys.stdout.flush()
writer = threading.Thread(target=writeall, args=(p,))
writer.start()
try:
while True:
d = sys.stdin.read(1)
if not d:
break
self._write(p, d.encode())
except EOFError:
pass
def _write(self, process, message):
process.stdin.write(message)
process.stdin.flush()
shell = LocalShell()
shell.run()