【问题标题】:Why subprocess does not terminate with Python 2.7 only?为什么 subprocess 不会仅以 Python 2.7 终止?
【发布时间】:2021-03-03 18:23:53
【问题描述】:

我有一个使用subprocess.Popen 生成进程的代码:

from subprocess import check_call, CalledProcessError, Popen, PIPE
cmd="while true; do echo 123; done | grep -m1 123"
proc = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
out, err = proc.communicate()

当我使用 Python 3.9.2 运行它时,它会按预期立即终止。但是,当我使用 Python 2.7 运行它时,它会挂起。似乎 Python 2.7 等待 shell 无限循环终止,但它永远不会终止。我也可以让这段代码在 Python 2.7 下终止吗?

【问题讨论】:

  • 它应该返回对我来说并不是很明显。 Popen 启动了一个 shell 进程。即使grep 已关闭stdout 句柄,该进程仍在运行。
  • grep 终止时,它也应该终止while true 循环。这可以在 bash 交互式 shell 中观察到。如我所见,这就是 Python 3.9.2 中发生的情况,但在 Python 2.7 中不会发生。

标签: python python-3.x python-2.7


【解决方案1】:

找到了 Python 2.7 的相关问题 Python subprocess.Popen blocks with shell and pipe。问题是在 Python 2.7 中SIGPIPE 信号默认被忽略,因此while true 循环忽略了grep 在第一次匹配时终止的事实。此https://bugs.python.org/issue1652 存在未解决的 Python 问题。在 Python 3 上,restore_signals=True 有一个额外的参数 subprocess.Popen,因此上面的代码按原样工作。对于 Python 2.7,可以修改为以这种方式恢复 SIGPIPE 信号:

from subprocess import check_call, CalledProcessError, Popen, PIPE
import signal

def restore_signals():
    signals = ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ')
    for sig in signals:
        if hasattr(signal, sig):
            signal.signal(getattr(signal, sig), signal.SIG_DFL)

cmd="while true; do echo 123; done | grep -m1 123"
proc = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, preexec_fn=restore_signals)
out, err = proc.communicate()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 2018-10-11
    • 2011-02-28
    相关资源
    最近更新 更多