【问题标题】:Custom Popen.communicate method gives wrong output自定义 Popen.communicate 方法给出错误的输出
【发布时间】:2020-07-06 13:24:46
【问题描述】:

让我们从考虑这段代码开始:

proc_stdin.py

import sys

if __name__ == '__main__':
    for i, line in enumerate(sys.stdin):
        sys.stdout.write(line)

test.py

import subprocess


def run_bad(target, input=None):
    proc = subprocess.Popen(
        target,
        universal_newlines=True,
        shell=True,
        stderr=subprocess.STDOUT,
        stdin=subprocess.PIPE if input else subprocess.DEVNULL,
        stdout=subprocess.PIPE,
    )

    if input:
        proc.stdin.write(input)
        proc.stdin.flush()
        proc.stdin.close()

    lines = []
    for line in iter(proc.stdout.readline, ""):
        line = line.rstrip("\n")
        lines.append(line)
    proc.stdout.close()

    ret_code = proc.wait()
    return "\n".join(lines)


def run_good(target, input):
    return subprocess.Popen(
        target,
        universal_newlines=True,
        shell=True,
        stderr=subprocess.STDOUT,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
    ).communicate(input=input)[0]


if __name__ == '__main__':
    lst = [
        "",
        "token1",
        "token1\n",
        "token1\r\n",
        "token1\n\n",
        "token1\r\n\ntoken2",
        "token1 token2",
        "token1\ntoken2",
        "token1\r\ntoken2",
        "token1\n\ntoken2",
        "token1\r\n\ntoken2",
        "token1 \ntoken2\ntoken2\n"
    ]
    cmd = "python proc_stdin.py"

    for inp in lst:
        a, b = run_bad(cmd, inp), run_good(cmd, inp)
        if a != b:
            print("Error: {} vs {}".format(repr(a), repr(b)))
        else:
            print("ok: {}".format(repr(a)))

输出:

ok: ''
ok: 'token1'
Error: 'token1' vs 'token1\n'
Error: 'token1\n' vs 'token1\n\n'
Error: 'token1\n' vs 'token1\n\n'
ok: 'token1\n\n\ntoken2'
ok: 'token1 token2'
ok: 'token1\ntoken2'
ok: 'token1\n\ntoken2'
ok: 'token1\n\ntoken2'
ok: 'token1\n\n\ntoken2'
Error: 'token1 \ntoken2\ntoken2' vs 'token1 \ntoken2\ntoken2\n'

我的问题是,为什么run_badrun_good 的输出在所有情况下都不相等?您将如何更改run_bad 函数以使输出等于run_good

您可能还想知道,为什么您不直接使用 Popen.communicate 来处理这种特殊情况或子流程模块中的其他帮助程序?好吧,在现实世界的情况下,我正在为 SublimeText3 创建一个插件,这迫使我坚持使用 python3.3(不能使用许多现代子进程的好东西)加上我想在阅读这些行时注入一些回调来自标准输出,这是我无法通过使用 Popen.communicate 方法(据我所知)做到的。

提前致谢。

【问题讨论】:

  • 请注意,您对communicate 的模拟可能会因长时间输入/输出而死锁。
  • @DavisHerring 是的,很好,我已经意识到了这一点,但我不知道超时的正确方法......对于我的特殊情况,我正在考虑在 Sublime 中杀死进程
  • @DavisHerring 现在我很好奇......也许一个正确的解决方案不是既不杀死也不让进程超时......而且,似乎https://stackoverflow.com/a/14617026/3809375 不会在跨平台方式。你对长输入/输出的死锁有什么建议吗?
  • 廉价、便携的方法是每个管道使用一个线程(所以 一个 额外线程与stdin=PIPE, stdout=PIPE, stderr=STDOUT)。

标签: python subprocess python-3.3


【解决方案1】:

如果您从每一行中删除换行符,然后将它们添加回行间,最后一个换行符(如果有)会发生什么情况? (在最后的换行符之后没有最后的空行,因为您的 iter 会丢弃它。)这就是 Python 的 readline(或行迭代)函数包含换行符的原因:它们是表示所必需的准确的文件结尾。

【讨论】:

    猜你喜欢
    • 2020-12-18
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    相关资源
    最近更新 更多