python-3.x - 在 Python 中写入生成的进程的重定向输入
问题描述
对不起,我真的不是蟒蛇人,但情况打击了我,这对你们蟒蛇人来说是非常明显的。
我正在尝试与生成的控制台进程进行交互通信(在我们的用例中,它是一个控制台程序,它与旧的但仍然很好的 HP 仪器进行通信,用于测量实验中的一些物理变量)。
我在这里找到了一些有见地的例子:
Running interactive program from inside python
但是当试图获得灵感时(我不想要那个计时器),我开始从头开始编写这个,使用通常存在于 windows 盒子上的 ftp.exe 程序进行测试,具有以下内容:
#!/usr/bin/python
import subprocess, sys
mystdout=sys.stdout
p = subprocess.Popen("ftp.exe", stdin=subprocess.PIPE, stdout=subprocess.PIPE) #, shell=True)
sys.stdout=p.stdin
print('bye\n'.encode())
sys.stdout=mystdout
print('done')
但print('bye\n'.encode())
结果是:
print('bye\n'.encode())
TypeError: a bytes-like object is required, not 'str'
我不能使用communicate()
subprocess 的方法,因为它似乎不是很有互动性(仅限一次)。
请你给我一个提示,我的笨蛋在哪里?这台机器在 Windows 上运行 Python 3.6.1,但更友好的 3.7.3 的 Linux 机器给出了相同的问候。
解决方案
有趣的是,我刚刚发现添加
universal_newlines=True
作为Popen()
解决我的问题的最后一个论点。我猜流不喜欢,print()
因为它是以二进制模式打开的。添加此标志以文本模式打开流。当我拥有它时,我将发布一个完整的示例,包括交互式通信。
编辑:
哦,现在我找到了更多与此问题相关的资源。
- 从 Python 中的子进程输出流进行非阻塞读取
- 错误:没有名为“fcntl”的模块
- 在 Python 中对 subprocess.PIPE 进行非阻塞读取
- 使用 Python 进行交互式输入/输出
- 在 Python 中运行交互式命令
在 Linux 上似乎更容易,因为有 fcntl 包允许使用非阻塞 read() 设置管道。不幸的是,它似乎在 Windows 上不可用 :( 我希望使用 peek() 调用,但令人惊讶的是,它也在管道上阻塞!:(
所以我们要么被线程困住,要么被现代难以阅读的异步/等待风格困住。
基于上面链接的灵感,我已经达到了以下简单的工作 ftp 示例:
#!/usr/bin/python
import time, sys, subprocess, threading, queue
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def getOutput(outQueue):
outStr = ''
try:
while True:
outStr+=outQueue.get_nowait()
except queue.Empty:
return outStr
p = subprocess.Popen("ftp.exe", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
outQueue = queue.Queue()
errQueue = queue.Queue()
outThread = threading.Thread(target=enqueue_output, args=(p.stdout, outQueue))
errThread = threading.Thread(target=enqueue_output, args=(p.stderr, errQueue))
outThread.daemon = True
errThread.daemon = True
outThread.start()
errThread.start()
p.stdin.write('status\n')
p.stdin.flush()
time.sleep(0.2)
errors = getOutput(errQueue)
output = getOutput(outQueue)
print("err:" + errors)
print("out:" + output)
time.sleep(2)
p.stdin.write('help\n')
p.stdin.flush()
time.sleep(0.2)
errors = getOutput(errQueue)
output = getOutput(outQueue)
print("err:" + errors)
print("out:" + output)
time.sleep(2)
p.stdin.write('bye\n')
p.stdin.flush()
time.sleep(0.2)
errors = getOutput(errQueue)
output = getOutput(outQueue)
print("err:" + errors)
print("out:" + output)
time.sleep(2)
print('done')
最后一点:当使用它与我自己的 c++ 程序进行通信时,我必须fflush(stdout)
在每次输出后发出。甚至换行符也没有帮助这些东西在不冲洗的情况下落入管道。
推荐阅读
- python - 以正确的日期格式将 SAS lib 导出到 csv(在 CSV 文件中)
- bash - 如何在 unix 中打印失败的挂载点?
- python - 如何在我的程序计算器中绑定键。特金特
- c++ - 在定义(.cpp 文件)中初始化静态浮点 constexpr 成员是否可能
- django-forms - 如何选择多个值而不使用 django 表单和 SelectMultiple 小部件进行控制?
- mysql - 如何规范化具有相似列名的表?
- android - 无法将对象传递给我的自定义复合控件
- android - 国家和民族的 Array.xml 列表
- jquery - 设置灯箱项目的顺序
- java - 如何在运行时更改此 TRUE 或 FALSE 值