自定义Popen.communicate方法给出错误的输出

问题描述 投票:1回答:1

让我们开始考虑以下代码:

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(不能使用许多现代子流程工具),而且我想在阅读代码时注入一些回调从stdout中获取,这是我无法使用Popen.communicate方法执行的(据我所知)。

提前感谢。

python subprocess python-3.3
1个回答
0
投票

如果从每行中删除换行符,然后将其重新添加到各行之间,那么最后一个换行符(如果有)会发生什么? (在最后一个换行符之后没有最后一个空行,因为您的iter会丢弃它。)这就是Python的readline(或行迭代)函数includes换行符的原因:必须用它们来表示换行符的结尾文件正确。

© www.soinside.com 2019 - 2024. All rights reserved.