【问题标题】:Python - Unable to pass an opened file to Popen as stdoutPython - 无法将打开的文件作为标准输出传递给 Popen
【发布时间】:2014-07-10 15:35:45
【问题描述】:

我目前正在尝试将 subprocess.Popen 对象的标准输出重定向到打开的文件,因此我遵循了许多网站上的说明,例如 this

但是,由于某种原因,Popen.stdout 没有正确分配

我的代码如下:

def foo(file):
    print(file)              # printA

    proc = subprocess.Popen('command, stdout=file) # i've tried with both shell=True/False
    print(proc)              # printB
    print(proc.stdout)       # printC
    return proc

def main():
    file = open('path', 'w')
    p = foo(file)
    print(p.stdout)          # printD   

结果如下

printA: <_io.TextIOWrapper name='path' mode='w' encoding='UTF-8'>
printB: <subprocess.Popen object at 0x161966d0>
printC: None
printD: None

根据我在 python 文档 here 中读到的内容,如果没有分配 PIPE,则 stdout 的默认值为 None。但是由于this 这里表明显然我们可以将打开的文件作为参数传递给标准输出,所以我不明白为什么我的代码不起作用。

请帮忙。

【问题讨论】:

  • printA 清楚地表明 open 返回的是 NOT 标准文件(带有 OS 文件描述符,这是子进程真正需要的)。为此,您必须传递一个真实文件。
  • @deets 你的意思是像 .log 或 .txt 文件?
  • W: 1,8:foo: 重新定义内置 'file' W: 10,4:main: 未使用的变量 'f'
  • 忘记我的答案 - 我不知道 io-modul 在这里的含义,它看起来像 StringIO 这样的内存包装器,它不起作用。可能@zmo 的回答不错。
  • 在 python 3 中,文件的类型为 io.textiowrapper

标签: python python-3.x subprocess stdout popen


【解决方案1】:

我运行了一个更简单的示例,这就是我发现的:

>>> p = subprocess.Popen('ls', stdout=open('moo','w'))
>>> str(p.stdout)
'None'

但是,文件“moo”确实包含我当前目录的内容。在来自用户@eryksun(见下面的 cmets)的有用提示并阅读源代码后,我意识到 p.stdout 变量将被分配 如果 PIPE 在 stdout 参数中传递。在所有其他情况下,它将设置为无,这正是上面示例所展示的。底线 - 一切都按预期工作。

另外,请注意,如果前面的答案建议是正确的,你会得到

<type 'file'>

在printA中,所以我认为前面的答案是不正确的。

【讨论】:

  • @eryksun - 你是对的。只有当您将 PIPE 作为参数传递时,Popen 中的 self.stdout 才会被设置,但本质上它并没有太大变化,因为作者所询问的内容是他想要的,所以这是一个“误报”。我会更新答案。
  • @eryksun - 我不在乎积分。周围有很多不合格的人,他们甚至没有解释原因就投反对票:) 感谢您提供代码链接 - 我很喜欢阅读它。
  • 您应该将 open 语句更改为上下文管理器,以避免在关闭文件时产生任何副作用...
  • 谢谢@zmo。上面这个简短示例的目的是演示重定向到 stdout 的工作原理,而不是提供一个完美的代码示例。
  • the documentation for Popen.stdout explicitly covers it;在这种情况下,您无需阅读源代码即可发现 p.stdout 为 None。请使用with-statement 作为文件。
【解决方案2】:

您的代码有一些缺陷,在下面更正:

def main():
    with open('path', 'w') as f:
        subprocess.Popen(['command'], stdout=f)

您将file 对象作为参数提供给您的函数,而不是f 对象。然后在您的函数中,您将遮蔽您提供给 Popen 的全局 file 对象,但顺便说一下,它是真正的 file 对象。

【讨论】:

  • 虽然在 py3 中没有更多的全局 file 对象。但是您的 SSCCE 仍然是错误的。
  • 我认为这是一个错字。您将在 PrintA 中获得不同的打印输出
  • 谢谢!!!,这确实有效。但是,我确实还有一个问题:我试图将 popen 对象分配给 x,并在程序退出之前终止了该进程。当我这样做时,文件不再被覆盖。似乎文件没有与输入一起写入,而是存储在缓冲区中,然后在最后写入文件。知道发生了什么吗?
  • 就是你说的,上下文管理器在退出块时将所有数据刷新到文件中。
  • @zmo 有没有办法让经理在捕获数据时刷新数据?而且,很抱歉,我不得不将接受的答案更改为 Oleg 的回答,eryksun 有道理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
相关资源
最近更新 更多