Python 由导入的模块生成的捕获子流程输出

Python 由导入的模块生成的捕获子流程输出,python,subprocess,stdout,Python,Subprocess,Stdout,注意:我知道我可以使用stdout=subprocess.PIPE捕获子流程输出 在我的例子中,子进程将由导入的模块启动,例如,youtube dl将为ffmpeg启动子进程,我希望捕获ffmpeg输出 我做了一个虚拟的工作场景来阐明我的观点 我有两个文件:m1.py我的模块和m2.py导入的库 m2.py import subprocess def run(): print('m2 module message will be caught by echo function too')

注意:我知道我可以使用stdout=subprocess.PIPE捕获子流程输出

在我的例子中,子进程将由导入的模块启动,例如,youtube dl将为ffmpeg启动子进程,我希望捕获ffmpeg输出

我做了一个虚拟的工作场景来阐明我的观点

我有两个文件:m1.py我的模块和m2.py导入的库

m2.py

import subprocess
def run():
    print('m2 module message will be caught by echo function too')
    cmd = ['ping', 'google.com']
    subprocess.Popen(cmd)
m1.py

终端输出:

m1 module message will be caught by echo function
m2 module message will be caught by echo function too

Pinging google.com [172.217.18.46] with 32 bytes of data:
Reply from 172.217.18.46: bytes=32 time=86ms TTL=53
Reply from 172.217.18.46: bytes=32 time=78ms TTL=53
out.txt

m1 module message will be caught by echo function
m2 module message will be caught by echo function too
从上面可以清楚地看到out.txt文件从两个模块接收到2 print语句,但无法获得其他输出


这里的问题是,我如何获得m2.py启动的ping命令的输出,当然我不能更改m2.py的代码,因为它是第三方库,每周更新一次。注意:这可能只是部分响应,因为它的操作系统级别较低。它在linux上对我有效,但我不能就windows或其他操作系统发表声明

使用echo函数重定向输出的尝试不起作用,因为这只是覆盖python进程中的写操作。 ping命令或第三方模块启动的任何命令都是一个新进程,它不会继承python环境,特别是不会继承重写的write函数

但是-当生成一个新进程时,它确实继承了stdout文件句柄,我指的是低级别的os文件句柄,对于unix上的stdout,它是1

我可以用以下代码重定向ping输出

import os

...
out2 = open('out2.txt', 'w')
fd = out2.fileno()  # here you get the low level file handle of the new file obj
os.dup2(fd, 1)      # here you are closing your stdout handle and setting it to out2

...
m2.run()     # the spawned ping command is now writing to out2
现在,这是重定向到文件对象。 我知道您想读取程序中的输出

要实现这一点,您可以在python中创建管道并改用该文件句柄:

pipein, pipeout = os.pipe()

注意,pipein和pipeout已经是低级文件句柄。要像使用python文件对象一样使用其中一个对象,您可以使用os.fdopenfd创建一个对象,只需返回子流程运行的结果并正常分配即可

平方米

m1


希望这有帮助

它看起来很有希望,只是在windows上测试了相同的代码,并在out2.txt中收集了所有输出,正如您所说,我只需要回显输出以将其用于gui,因此我将检查os.pipe并让您知道结果。幸运的是,我无法更改导入模块m2.py中的任何代码,它是第三方库,但出于好奇,我尝试了你的代码,它抛出了一个错误TypeError:“Popen”对象不是很糟糕,我忘了添加通信。这就是导致输出错误的原因。我已对我的回答作了更正。如果您确定子流程对象是从m2模块返回的,那么这应该有效。不,子流程对象不是从m2模块返回的,无论如何,谢谢
pipein, pipeout = os.pipe()
import subprocess
def run():
    print('m2 module message will be caught by echo function too')
    cmd = ['ping', 'google.com']
    return subprocess.Popen(cmd)
import sys
import m2

# this is a redirection function to echo stdout to a file
def echo(text):
    with open('out.txt', 'a') as f:
        f.write(text)

    sys.stdout.write = original
    sys.stdout.write(text)
    sys.stdout.write = echo

original = sys.stdout.write
sys.stdout.write = echo

print('m1 module message will be caught by echo function')
process_object = m2.run()
output, err = process_object.communicate()
print(output, err)