python subprocess proc.stderr.read() 引入多余行?

5 投票
2 回答
7728 浏览
提问于 2025-04-17 05:31

我想运行一些命令,并获取输出到错误信息(stderr)中的内容。我有两个版本的函数来实现这个功能。

def Getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""

    import sys
    mswindows = (sys.platform == "win32")

    import os
    if not mswindows:
        cmd = '{ ' + cmd + '; }'

    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text  

还有第二个版本。

def Getstatusoutput2(cmd):
    proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    return_code = proc.wait()
    return return_code, proc.stdout.read(), proc.stderr.read()

第一个版本的输出正如我所期待的那样,能正确打印错误信息。而第二个版本在每一行后面多打印了一行空白。我怀疑这是因为第一个版本中的 text[-1:] 这一行……但我在第二个版本中似乎无法做到类似的处理。有没有人能告诉我,我需要做些什么才能让第二个函数的输出和第一个一样,没有多余的空行(包括最后一行)?

更新:这是我打印输出的方式。

      status, output, error = Getstatusoutput2(cmd)
      s, oldOutput = Getstatusoutput(cmd)
      print "oldOutput = <<%s>>" % (oldOutput)
      print "error = <<%s>>" % (error)

2 个回答

2

你可以使用 .strip() 方法:

def Getstatusoutput2(cmd):
    proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    return_code = proc.wait()
    return return_code, proc.stdout.read().strip(), proc.stderr.read().strip()

Python string 文档

string.strip(s[, chars])

这个方法会返回一个新的字符串,去掉了开头和结尾的字符。如果你不提供 chars 或者给它传 None,那么它会去掉空白字符。若你提供了 chars,并且它不是 None,那么 chars 必须是一个字符串;这个字符串中的字符会被从调用这个方法的字符串的两端去掉。

string.whitespace

这是一个包含所有被认为是空白字符的字符串。在大多数系统中,这包括 空格制表符换行符回车符分页符垂直制表符

2

你可以使用 subprocess.check_output([cmd], stderr=STDOUT) 来捕获所有输出。

如果你想分别捕获标准输出和错误输出,可以使用 .communicate()

stdout, stderr = Popen([cmd], stdout=PIPE, stderr=PIPE).communicate()

如果你想获取所有行而不在最后加换行符,可以调用 stderr.splitlines()

为了避免在打印时多出一个换行符,如果变量后面已经有换行符,可以在打印语句中加上 ','

print line,

或者如果你使用 print() 函数:

print(line, end='')

注意

你的 Getstatusoutput2() 方法会在 cmd 产生足够多的输出时阻塞,所以建议使用上面的解决方案:

>>> len(Getstatusoutput2(['python', '-c',"""print "*"*2**6"""])[1])
65
>>> len(Getstatusoutput2(['python', '-c',"""print "*"*2**16"""])[1])

Popen.wait() 文档

等待子进程结束。设置并返回返回码属性。

警告:当使用 stdout=PIPE 和/或 stderr=PIPE,并且子进程生成的输出足够多以至于阻塞等待操作系统管道缓冲区接受更多数据时,这会导致死锁。使用 communicate() 可以避免这个问题。

相关内容 使用 communicate() 而不是 stdin.write()、stdout.read() 或 stderr.read()

撰写回答