捕获未写入stdout和stderr的控制台输出?
我有一个叫做pregeocode的Windows应用程序(我们没有源代码),这个程序基本上是把地理编码写入一个输入文件。这个程序实际上不会在控制台上输出任何东西,除非出现错误。通常这个程序是通过一个小的Python程序来调用的(它处理参数等,做一些有趣的预处理)。
我们通过检查输出文件是否被创建来判断程序是否失败(它总是返回0,无论结果如何)。但是当它失败时,子进程显示没有任何内容被打印到错误输出或标准输出上。(它大约能成功处理一百个左右的请求,通常只有一个会出错,但我很想知道出错的原因是什么)
这个小的Python脚本是通过subprocess.Popen来调用这个应用程序的:
argslist = [r'C:\workspace\apps\pregeocode.exe', '-in', inputfilename, '-out', outputfilename, '-gcp', gcp_file]
p = subprocess.Popen(argslist, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
print str(p.communicate())
输出结果是:
('', '')
但是如果我在命令行中手动运行这个程序,使用相同的参数,我得到的输出是:
45 IMAGE_EXTENT_TOO_SMALL
(大约有60种不同的错误信息,其中45个表示错误编号)
使用shell=True这个参数并没有改变任何情况,我也在网上找不到关于这个问题的任何信息。这个exe文件是很久以前内部制作的,我们没有它的源代码,所以我无法查看它是如何打印出这些信息的。
那么,为什么子进程实际上无法捕获这个程序的标准输出或错误输出呢?
编辑
os.system(" ".join(argslist))
正确打印出错误信息:
45 IMAGE_EXTENT_TOO_SMALL
编辑 2
结果发现这个应用程序使用了ERDAS的工具包。它们的工具包将所有的标准输出和错误输出重定向到它们的日志子系统。然后日志子系统通过“CON”重新输出这些信息。
2 个回答
你是在用Python 2.5或者早期的2.6版本吗?
你可以试试这个subprocess.check_output,把错误信息也重定向到标准输出:
out_err = subprocess.check_output(argslist, stderr=subprocess.STDOUT)
如果out_err同时获取了输出和错误信息,你可能需要把标准输出和错误输出重定向到文件对象,然后再从这些文件对象中读取内容(因为Windows没有像Unix那样的管道):
fout = open('fout', 'w')
ferr = open('ferr', 'w')
p = subprocess.Popen(argslist, stdout=fout, stderr=ferr)
p.wait()
fout.close()
ferr.close()
因为错误信息并没有出现在 stdout
或 stderr
上,所以我猜这个程序可能在用Windows系统中打开某种类似于 /dev/tty
的东西。 在Unix系统中,你可以通过小心使用 pty.openpty
来拦截这个,但据我所知,Python在Windows上没有类似的支持。你可以试试 Expect for Windows。