需要一种更好的方法从python执行控制台命令并记录结果

时间:2009-02-18 02:02:08

标签: python logging command-line

我有一个需要执行多个命令行实用程序的python脚本。 stdout输出有时用于进一步处理。在所有情况下,我想记录结果并在检测到错误时引发异常。我使用以下函数来实现此目的:

def execute(cmd, logsink):
    logsink.log("executing: %s\n" % cmd)
    popen_obj = subprocess.Popen(\
          cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (stdout, stderr) = popen_obj.communicate()
    returncode = popen_obj.returncode
    if (returncode <> 0):
       logsink.log("   RETURN CODE: %s\n" % str(returncode))
    if (len(stdout.strip()) > 0):
       logsink.log("   STDOUT:\n%s\n" % stdout)
    if (len(stderr.strip()) > 0):
       logsink.log("   STDERR:\n%s\n" % stderr)
    if (returncode <> 0):
       raise Exception, "execute failed with error output:\n%s" % stderr
    return stdout

“logsink”可以是任何带有log方法的python对象。我通常使用它来将日志记录数据转发到特定文件,或将其回显到控制台,或两者,或其他...

这非常好用,除了三个问题,我需要比communication()方法提供更细粒度的控制:

  1. stdout和stderr输出可以交错显示 控制台,但上面的功能日志 他们分开。这个可以 复杂的解释 登录。如何记录stdout和stderr 行交错,顺序相同 因为它们是输出的?
  2. 以上功能只会记录 命令输出后命令输出 完成。当命令陷入无限循环或由于某些其他原因需要很长时间时,这会使问题的诊断变得复杂。如何在命令仍在执行的同时实时获取日志?
  3. 如果日志很大,它可以得到 很难解释哪个命令 生成哪个输出。有没有 用每个行作为前缀的方法 某事(例如,第一个字) cmd字符串后跟:)。

4 个答案:

答案 0 :(得分:5)

如果您只想将输出放在文件中以供日后评估,则可以重定向到文件。

您已经定义了stdout = / stderr = methods执行的进程的stdout / stderr。

在您的示例代码中,您只需重定向到脚本当前out / err分配。

subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

sys.stdout和sys.stderr只是文件类对象。 正如关于sys.stdout的文档文档所提到的,“任何对象都是可接受的,只要它有一个带有字符串参数的write()方法。”

f = open('cmd_fileoutput.txt', 'w')
subprocess.Popen(cmd, shell=True, stdout=f, stderr=f)

所以你只需要给它一个带有write方法的类来重定向输出。

如果您希望控制台输出和文件输出都可以创建一个类来管理输出。

一般重定向:

# Redirecting stdout and stderr to a file
f = open('log.txt', 'w')
sys.stdout = f
sys.stderr = f

制作重定向课程:

# redirecting to both
class OutputManager:
    def __init__(self, filename, console):
        self.f = open(filename, 'w')
        self.con = console

    def write(self, data):
        self.con.write(data)
        self.f.write(data)

new_stdout = OutputManager("log.txt", sys.stdout)

交错取决于缓冲,因此您可能会或可能不会得到您期望的输出。 (您可以关闭或减少使用的缓冲,但我现在不记得如何)

答案 1 :(得分:2)

您可以查看pexpect(http://www.noah.org/wiki/Pexpect

它解决了1)和2)开箱即用,输出前缀可能有点棘手。

答案 2 :(得分:1)

另一个选择:

def run_test(test_cmd):
    with tempfile.TemporaryFile() as cmd_out:
        proc = subprocess.Popen(test_cmd, stdout=cmd_out, stderr=cmd_out)
        proc.wait()
        cmd_out.seek(0)
        output = "".join(cmd_out.readlines())
    return (proc.returncode, output)

这会根据需要将stdoutstderr交错显示在一个方便您打开的真实文件中。

答案 3 :(得分:1)

这绝不是一个完整或详尽的答案,但也许您应该查看Fabric模块。

http://docs.fabfile.org/0.9.1/

使shell命令的并行执行和错误处理变得相当容易。