首页 > 解决方案 > python subprocess.run 如果你重定向stdout/stderr,它会错误退出而不是工作

问题描述

#!/usr/bin/env python3

import subprocess
import os

if False:
    # create log file.
    kfd = os.open( 'kk.log', os.O_WRONLY )

    # redirect stdout & err to a log file.
    os.close(1)
    os.dup(kfd)
    os.close(2)
    os.dup(kfd)

subprocess.run([ "echo", "hello world"], check=True )

% ./kk.py
hello world
% 

以上工作正常,但如果您尝试编辑文件,并将 False 替换为 true:

% ./kk.py
% more kk.log
Traceback (most recent call last):
File "./kk.py", line 16, in <module>
  subprocess.run([ "echo", "hello world"], check=True )
File "/usr/lib/python3.6/subprocess.py", line 418, in run
  output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['echo', 'hello world']' returned 

非零退出状态 1. %

我们没有得到输出,并且进程错误退出......我本来希望它能够正常工作,写入 kk.log。

标签: linuxpython-3.xsubprocess

解决方案


你可能想说这样的话:

#!/usr/bin/env python3

import subprocess
import os

if True:
    # create log file.
    kfd = os.open( 'kk.log', os.O_WRONLY | os.O_CREAT )

    # redirect stdout & err to a log file.
    os.dup2(kfd, 1)
    os.dup2(kfd, 2)

subprocess.run([ "echo", "hello world"], check=True )

注意使用os.dup2. 有两个原因。首先,生成的文件描述符是可继承的。您的 echo 实际上没有打开stdout/-err因此失败(您可以在 shell 中运行以下命令来回显,只需关闭 stdout 以检查行为:)/bin/echo hello world 1>&-。另请注意,如果我关闭stdout(1),则最低描述符(和 的结果os.dup)可能并不总是正确的 1。有人可能stdin在运行脚本之前关闭了您的 (0)(同样适用stderr)。

文件描述符继承的背景故事在PEP-446中。

我还添加了os.O_CREAT,因为我第一次尝试重现您的问题的失败是不存在的 kk.log。

不用说,除非尝试在操作系统中使用接口(也许作为练习),否则我想您通常应该坚持subprocess自己。


推荐阅读