如何从Python脚本捕获Python解释器和/或者CMD.EXE的输出?

时间:2020-03-05 18:42:33  来源:igfitidea点击:
  • 是否可以从Python脚本捕获Python解释器的输出?
  • 是否可以从Python脚本捕获Windows CMD的输出?

如果是这样,我应该研究哪个librar(y | ies)?

解决方案

回答

我们问的是哪种情况?

我们是否要捕获从命令行启动的程序的输出?

如果是这样,那么这是如何执行它:

somescript.py | your-capture-program-here

并读取输出,只需从标准输入中读取。

另一方面,如果我们正在程序中执行该脚本或者cmd.exe或者类似程序,并且想要等到脚本/程序完成并捕获其所有输出,则需要查看库调用我们用来启动该外部程序的调用,很可能是有一种方法要求它给我们一些读取输出并等待完成的方法。

回答

我们想要子流程。在17.1.1中专门查看Popen,并在17.1.2中进行通信。

回答

如果我们要谈论的是脚本的"父级" python解释器或者CMD.exe,则不可能,这是不可能的。在每个类似POSIX的系统中(似乎现在我们正在运行Windows,并且可能有一些我不知道的怪癖,YMMV),每个进程都有三个流,标准输入,标准输出和标准错误。缺省情况下(在控制台中运行时)将它们定向到控制台,但是可以使用管道符号进行重定向:

python script_a.py | python script_b.py

这将脚本a的标准输出流与脚本B的标准输入流联系在一起。在此示例中,标准错误仍然传递到控制台。请参阅Wikipedia上有关标准流的文章。

如果我们正在谈论子进程,则可以像这样从python启动它(如果需要双向通信,stdin也可以选择):

import subprocess
# Of course you can open things other than python here :)
process = subprocess.Popen(["python", "main.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
x = process.stderr.readline()
y = process.stdout.readline()
process.wait()

有关管理流程的信息,请参见Python子流程模块。为了进行通信,将process.stdin和process.stdout管道视为标准文件对象。

对于管道,从lassevk的标准输入中读取建议我们执行以下操作:

import sys
x = sys.stderr.readline()
y = sys.stdin.readline()

sys.stdin和sys.stdout是上述在sys模块中定义的标准文件对象。我们可能还想看看管模块。

在我的示例中,使用readline()读取数据是一种获取数据的简单方法。如果输出不是面向行的或者不确定的,则可能要调查轮询,但不幸的是,该轮询在Windows中不起作用,但我敢肯定还有其他选择。

回答

实际上,我们绝对可以,而且它既美丽,丑陋又疯狂!

我们可以用收集输出的StringIO对象替换sys.stdout和sys.stderr。

这是一个示例,将其另存为evil.py:

import sys
import StringIO

s = StringIO.StringIO()

sys.stdout = s

print "hey, this isn't going to stdout at all!"
print "where is it ?"

sys.stderr.write('It actually went to a StringIO object, I will show you now:\n')
sys.stderr.write(s.getvalue())

当我们运行该程序时,我们将看到:

  • 什么都没有输出到stdout(通常将打印输出到哪里)
  • 写入stderr的第一个字符串是以'It'开头的字符串
  • 接下来的两行是在StringIO对象中收集的行

像这样替换sys.stdout / err是所谓的monkeypatching的应用程序。是否"支持"此方法的意见可能会有所不同,这绝对是一个丑陋的破解,但是当尝试将外部内容包装一两次时,它就节省了我的培根。

在Linux(而非Windows)上进行了测试,但它也应该可以正常工作。让我知道它是否适用于Windows!

回答

我想我可以为问题的第一部分指出一个好的答案。

1.  Is it possible to capture Python interpreter's output from a Python
  script?

答案是"是",我个人希望从PEP 343-" with"声明文档中的示例中得出以下结论。

from contextlib import contextmanager
import sys

@contextmanager
def stdout_redirected(new_stdout):
    saved_stdout = sys.stdout
    sys.stdout = new_stdout
    try:
        yield None
    finally:
        sys.stdout.close()
        sys.stdout = saved_stdout

像这样使用:

with stdout_redirected(open("filename.txt", "w")):
    print "Hello world"

它的一个不错的方面是,它可以仅在脚本执行的一部分而不是整个执行范围内有选择地应用,并且即使在其上下文中引发了未处理的异常时,它也仍然有效。如果在首次使用后以追加模式重新打开文件,则可以将结果累积到单个文件中:

with stdout_redirected(open("filename.txt", "w")):
    print "Hello world"

print "screen only output again"

with stdout_redirected(open("filename.txt", "a")):
    print "Hello world2"

当然,以上内容也可以扩展为还将sys.stderr重定向到相同或者另一个文件。另请参阅有关相关问题的答案。