使用 BytesIO 作为 stdout/stderr 目标 subprocess.run

Using BytesIO as stdout/stderr target for subprocess.run

我想 运行 一个子进程并将 stdout 和 stderr 重定向到不同的目标。 subprocess.run 方法允许在内存中捕获输出(使用参数 capture=True)或通过向参数 stdoutstderr 提供类似文件的值来重定向到文件中。我需要将 stdout 直接重定向到一个文件中,但想要捕获 stderr 以便我可以将错误提供给日志系统。我认为 BytesIO 非常适合作为类似文件的目标进行捕获,然后处理其中的内容。但是当我 运行 这个代码时:

temp_file_like = BytesIO(b'')
subprocess.run(
    arguments, check=True, shell=False,
    stdout=target_file_handle, stderr=temp_file_like
)
for line in str(temp_file_like.getvalue()).split("\n"):
    logger.warning(line)

(代码已简化)

我收到错误:

File "C:\path\to\script.py", line 143, in run_with_redirect
    stdout=target_file_handle, stderr=temp_file_like
File "C:\Users\username\AppData\Local\Programs\Python\Python37\lib\subprocess.py", line 488, in run
    with Popen(*popenargs, **kwargs) as process:
File "C:\Users\username\AppData\Local\Programs\Python\Python37\lib\subprocess.py", line 753, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
File "C:\Users\username\AppData\Local\Programs\Python\Python37\lib\subprocess.py", line 1106, in _get_handles
    errwrite = msvcrt.get_osfhandle(stderr.fileno())
io.UnsupportedOperation: fileno

在我看来,虽然 subprocess.run 应该接受文件句柄,但 BytesIO 实例不足以像文件一样被接受为目标。有没有办法只捕获一个流,同时将另一个流重定向到一个文件中,而不必使用磁盘上的临时文件?

可能你应该使用 subprocess.PIPE 作为 stdout,同时仍然让 stderr 指向临时文件句柄,然后通过 proc.stdout.read():

捕获 stdout
proc = subprocess.Popen(
    arguments,
    check=True,
    shell=False,
    stdout=subprocess.PIPE,
    stderr=temp_file_like
)
output = proc.stdout.read()