如何为subprocess.call创建自定义输出流

如何为subprocess.call创建自定义输出流

问题描述:

我想通过定义我自己的输出流实时输出subprocess.call,但它似乎不工作。如何为subprocess.call创建自定义输出流

原因:我想运行一个子进程,并得到该呼叫的输出到标准输出(实时这样我就可以看剧本,看目前的进展),以及它记录到文件

子。潘岳:

import time 

while True: 
    print("Things") 
    time.sleep(1) 

mainprocess.py

import subprocess 
import io 

class CustomIO(io.IOBase): 
    def write(self, str): 
     print("CustomIO: %s"%str) 
     # logging to be implemented here 

customio = CustomIO() 
subprocess.call(["python3", "print_process.py"], stdout=customio) 

但是当我运行这段代码我收到此错误信息:

Traceback (most recent call last):         
    File "call_test.py", line 9, in <module>       
     subprocess.call(["python3", "print_process.py"], stdout=customio) 
    File "/usr/lib/python3.4/subprocess.py", line 537, in call   
     with Popen(*popenargs, **kwargs) as p:       
    File "/usr/lib/python3.4/subprocess.py", line 823, in __init__  
     errread, errwrite) = self._get_handles(stdin, stdout, stderr)  
    File "/usr/lib/python3.4/subprocess.py", line 1302, in _get_handles 
     c2pwrite = stdout.fileno()          
io.UnsupportedOperation: fileno 

那么,任何人有任何线索,如果这是可能的?

我是否继承了错误的基类?

我是不是重载正确的方法?

还是我完全不合格,应该以完全不同的方式进行讨论?

+1

子过程期望一个真正的文件对象与真正的os文件描述符,尝试PIPE – georgexsh

如果您想处理子流程的输出,您需要通过stdout=subprocess.PIPE。但是,call()run()都将等到该过程完成后才能使用,因此无法使用这些功能实时处理它。

您需要使用subprocess.Popen

import subprocess as sp 

def handle_output(output_line): 
    ... 

my_process = sp.Popen(["python3", "print_process.py"], 
         stdout=sp.PIPE, 
         universal_newlines=True) # changes stdout from bytes to text 

for line in my_process.stdout: 
    handle_output(line) 

my_process.wait() 

更新:确保刷新输出缓冲区在你的孩子的过程:

while True: 
    print("Things", flush=True) 
    time.sleep(1) 
+0

这似乎并没有实时处理输出吗?当我运行它时,它会等待子流程在打印之前完成 – Bobbzorzen

+0

我的歉意 - 出于某种原因,当我用'[“yes”]测试时它工作。查看更新。 – Phydeaux

+0

不错,有没有办法做到这一点,而无需在子进程中添加刷新。在我的真实情况下,它不是一个python脚本,而是一个我无法控制的程序。 – Bobbzorzen

你需要用文件中指定和开放的流描述。 fileno没有为io.IOBase实现,因为这只是在内存中的数据流:

Frequently Used Arguments

stdinstdoutstderr指定执行程序的标准 输入,标准输出和标准错误文件句柄,分别。 有效值为PIPE,DEVNULL,现有文件描述符( 正整数),现有文件对象和NonePIPE表示 应该创建一条给孩子的新管道。 DEVNULL表示 将使用专用文件os.devnull。使用默认设置 None,不会发生重定向;

因此,您可能使用套接字,管道和打开文件作为stdout,文件描述符作为stdout传递给子进程。虽然我没有用subprocess.Popen套接字,但我希望它们能够工作,我相信这里重要的是该子文件描述符,而不是文件描述符指向的对象类型。