使用子进程重定向shell输出

时间:2011-07-03 02:39:40

标签: python linux subprocess

我有一个调用很多shell函数的python脚本。该脚本可以从终端以交互方式运行,在这种情况下,我想立即显示输出,或者由crontab调用,在这种情况下,我想通过电子邮件发送错误输出。

我编写了一个用于调用shell函数的辅助函数:

import subprocess
import shlex
import sys

def shell(cmdline, interactive=True):
    args = shlex.split(cmdline.encode("ascii"))
    proc = subprocess.Popen(args, stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    val = proc.communicate()
    if interactive is True:
        if proc.returncode:
            print "returncode " + str(proc.returncode)
            print val[1]
            sys.exit(1)
        else:
            print val[0]
    else:
        if proc.returncode:
            print ""
            # send email with val[0] + val[1]

if __name__ == "__main__":
    # example of command that produces non-zero returncode
    shell("ls -z")

我遇到的问题是双重的。

1)在交互模式下,当shell命令需要一段时间才能完成时(例如几分钟),直到命令完全完成后才会看到任何内容,因为communic()缓冲区输出。有没有办法在输入时显示输出,并避免缓冲?我还需要一种检查返回码的方法,这就是我使用communication()的原因。

2)我调用的一些shell命令可以产生大量输出(例如2MB)。 communication()的documentation表示“如果数据大小很大或无限制,请不要使用此方法。”有谁知道“大”有多大?

1 个答案:

答案 0 :(得分:2)

1)当您使用通信时,您捕获子进程的输出,因此不会向您的标准输出发送任何内容。在子进程完成时看到输出的唯一原因是你自己打印它。

由于您希望在运行时看到它而不捕获它或捕获所有内容并仅在最后执行某些操作,您可以通过离开 stdout 来更改它在交互模式下的工作方式和 stderr 。这使得子进程使用与程序相同的流。您还必须通过调用等待来替换对通信的调用:

if interactive is True:
    proc = subprocess.Popen(args)
    proc.wait()
    if proc.returncode:
        print "returncode " + str(proc.returncode)
        sys.exit(1)
else:
    proc = subprocess.Popen(args, stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    val = proc.communicate()
    if proc.returncode:
        print ""
        # send email with val[0] + val[1]

2)太大“太大而无法存储在内存中”,所以这一切都取决于很多因素。如果在您的情况下临时存储2MB的数据是可以的,那么就没什么好担心的了。