【问题标题】:Popen([...], stderr=PIPE) ignores input() message from spawned python programPopen([...], stderr=PIPE) 忽略来自生成的 python 程序的 input() 消息
【发布时间】:2023-03-08 17:53:01
【问题描述】:

我有一个文件通过 Popen() 运行另一个文件。

# a.py
import subprocess

p = subprocess.Popen(['python3','/home/scotty/b.py'], 
stderr=subprocess.PIPE)
p.wait()

# b.py
input('???')

当我运行 a.py "???"没有出现,但提示仍然有效......为什么?我该如何解决?

如果我删除 stderr=subprocess.PIPE 然后“???”确实出现了。

根据文档,输入的输出“写入标准输出”,我没有触及标准输出。

【问题讨论】:

  • Popen 之后,您应该调用p.communicate()。请参阅this page,它几乎涵盖了子流程模块的所有基本用例。
  • @gribouillis 老实说,我不使用communicate() 的原因是因为我希望即使按下ctrl-c 也能够捕获stderr。通过通信,我无法在键盘中断后收到它的返回值。 (我也没有使用 wait(),仅用于示例)
  • 如果您不使用communicate()wait(),您的程序如何等待p 完成?我想要一个 mvce...
  • @gribouillis 我正在尝试直接从 p.stderr 使用 select.select 和 rad

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


【解决方案1】:

似乎在您的示例中,一切都好像为 stderr 而不是为 stdout 打开管道具有将 stdout 重定向到 stderr 的效果,因为在我所做的测试中,stderr 接收输入的提示。

以下是在 linux 中适用于我的代码。它可能过于复杂,因为我使用的是 socketpairs,这当然不是必需的,但至少它很健壮并且可以工作。

##################################
# a.py

import subprocess
import socket
import select

esock, echildsock = socket.socketpair()
osock, ochildsock = socket.socketpair()
p = subprocess.Popen(['python3','b.py'], 
    stderr=echildsock.fileno(),
    stdout=ochildsock.fileno())

while p.poll() is None:
    r, w, x = select.select([esock, osock],[],[], 1.0)
    if not r:
        continue # timed out
    for s in r:
        print('stdout ready' if s is osock else 'stderr ready')
        data = s.recv(1024)
        print('received', data.decode('utf8'))
osock.shutdown(socket.SHUT_RDWR)
osock.close()
esock.shutdown(socket.SHUT_RDWR)
esock.close()

##################################
# b.py

res = input('???')
print('in b:', res)

【讨论】:

  • 我不相信有任何重定向正在进行。向 stderr 发送提示是完全正常的做法——例如,shell 提示会发送到那里;根据定义,提示是用户的状态信息,而不是输出内容。
  • 但是python的输入提示转到stdout。它在文档中,可以轻松测试。但在这种情况下,stderr 实际上会收到提示。我们或许可以通过打印一些输出来做更多的测试。
  • 我显然在阅读不同的文档——我在评论之前查看的文档没有指定标准输出 标准错误。但是,查看源代码,行为分支取决于我们是否有 TTY(以及提示是否实际上由 libreadline 执行)。
  • 嗯,我不完全确定有什么不同,但它对我有用,非常感谢!!
猜你喜欢
  • 1970-01-01
  • 2019-11-20
  • 2012-09-18
  • 1970-01-01
  • 2010-12-22
  • 2022-01-24
  • 1970-01-01
  • 2011-01-19
  • 2011-06-15
相关资源
最近更新 更多