如何从Python脚本捕获Python解释器和/或CMD.EXE的输出?
- 是否有可能捕获Python脚本Python解释器的输出?
- 是否可以从Python脚本中捕获Windows CMD的输出?
如果是这样,我应该看看哪个图书馆(y | ies)?如何从Python脚本捕获Python解释器和/或CMD.EXE的输出?
如果你正在谈论的Python解释器或cmd.exe,这就是你的脚本的“父”,则没有,这是不可能的。在每一个类似POSIX的系统中(现在你正在运行Windows,看起来,这可能有一些我不知道的怪癖,YMMV),每个进程有三个流,标准输入,标准输出和标准错误。卜默认这些被定向到控制台,但重定向可以使用管道符号(在控制台上运行时):
python script_a.py | python script_b.py
这关系脚本的标准输出流至脚本B的标准输入流在这个例子中,标准错误仍然在控制台上。请参阅维基百科上关于standard streams的文章。
如果你在谈论一个子进程,你可以从Python启动它,像这样(标准输入也是一种选择,如果你想双向通信):
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的subprocess模块管理流程。对于通信,process.stdin和process.stdout管道被认为是标准的file objects。
对于管道的使用,从标准输入读为lassevk建议你做这样的事情:
import sys
x = sys.stderr.readline()
y = sys.stdin.readline()
sys.stdin和sys.stdout的是标准的文件对象如上所述,在sys定义模块。您可能还想看看pipes模块。
用的ReadLine()作为我的例子中读数据,虽然获取数据的一个非常原始的方法。如果输出不是面向行或不确定的,你可能想看看polling,但不幸的是它不能在Windows中工作,但我确信有一些替代方法。
在哪些方面你问?
你们是不是要捕获从你在命令行上启动一个程序的输出?
如果是这样,那么这是如何执行它:
somescript.py | your-capture-program-here
和读取输出,从标准输入刚才读。
如果,另一方面,你执行该脚本或cmd.exe,或类似从您的程序中,并要等到脚本/程序已完成,并捕获所有的输出,那么你需要看看你用来启动外部程序的库调用,很可能有办法让它给你一些方法来读取输出并等待完成。
其实,你一定可以,同时它又美又丑又疯了!
您可以用收集输出的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())
当你运行这个程序,你会发现:
- 没事就去到标准输出(其中打印通常版画)
- 写入stderr的第一个字符串是以'It'开头的字符串
- 接下来的两行是在StringIO对象中收集的那一行
像这样替换sys.stdout/err是所谓的monkeypatching的应用程序。无论这种“支持”是什么,意见可能会有所不同,它绝对是一种丑陋的黑客攻击,但它在试图环绕外部事物一次或两次时拯救了我的培根。
在Linux上进行测试,而不是在Windows上进行测试,但它应该也能正常工作。让我知道它是否适用于Windows!
我想我可以指出你的问题的第一部分的一个很好的答案。
1. 是否有可能从一个Python脚本 捕捉Python解释器的输出?
答案是“是”,并亲自我喜欢从PEP 343 -- The "with" Statement文档中的例子下面举。
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
相同或另一个文件。另请参阅此answer相关问题。
请注意,使用subprocess.Popen()调用Python时,传递“-u”标志通常会有帮助,该标志禁用stdin/stdout/stderr上的缓冲。当孩子开始读取标准输入时,如果输出已被重定向到管道,Python不会自动刷新标准输出,因此您可以最终阻止永久读取缓冲的输出。我遇到了这个问题,试图包装/自动化pdb。 – 2011-11-18 16:29:49