【发布时间】:2020-06-09 17:32:01
【问题描述】:
我正在尝试制作一个以可执行文件名称作为参数的程序,运行可执行文件并报告该运行的输入和输出。例如,考虑一个名为“circle”的子程序。我的程序需要运行以下内容:
$ python3 capture_io.py ./circle 输入圆半径:10 区域:314.158997 [('output', '输入圆的半径:'), ('input', '10\n'), ('output', '面积: 314.158997\n')]我决定使用pexpect 模块来完成这项工作。它有一个名为interact 的方法,可以让用户与子程序进行交互,如上所示。它还需要 2 个可选参数:output_filter 和 input_filter。来自文档:
output_filter将传递子进程的所有输出。input_filter将传递来自用户的所有键盘输入。
这是我写的代码:
capture_io.py
import sys
import pexpect
_stdios = []
def read(data):
_stdios.append(("output", data.decode("utf8")))
return data
def write(data):
_stdios.append(("input", data.decode("utf8")))
return data
def capture_io(argv):
_stdios.clear()
child = pexpect.spawn(argv)
child.interact(input_filter=write, output_filter=read)
child.wait()
return _stdios
if __name__ == '__main__':
stdios_of_child = capture_io(sys.argv[1:])
print(stdios_of_child)
circle.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
float radius, area;
printf("Enter radius of circle: ");
scanf("%f", &radius);
if (radius < 0) {
fprintf(stderr, "Negative radius values are not allowed.\n");
exit(1);
}
area = 3.14159 * radius * radius;
printf("Area: %f\n", area);
return 0;
}
产生以下输出:
$ python3 capture_io.py ./circle 输入圆半径:10 区域:314.158997 [('output', '输入圆的半径:'), ('input', '1'), ('output', '1'), ('input', '0'), ('output', '0'), ('input', '\r'), ('output', '\r\n'), ('output', '区域: 314.158997\r\n')]您可以从输出中观察到,输入是逐个字符处理的,并且还会作为输出回显,这会造成如此混乱。是否可以更改此行为,以便我的 input_filter 仅在按下 Enter 时运行?
或者更一般地说,实现我的目标的最佳方式是什么(有或没有pexpect)?
【问题讨论】:
-
Linux 有相关的实用程序
script(检查--log-in和--log-out选项)和tee。 -
@VPfB 我将在我无法控制的机器上运行此代码。所以要求另一个程序对我不利。即使在我的计算机中,我也找不到
--log-in和--log-out选项。 (script from util-linux 2.31.1) -
@igrinis 我认为它并没有达到我想要的效果(至少我在阅读时是这样认为的),而且过于复杂。
-
@Asocia 好的,我不确定哪种解决方案适合您的需求。许多人更喜欢现有的工具。
--log-in是对的,它是最近在 2.35 中添加的。
标签: python python-3.x fork pexpect pty