我在python中包含一个大型项目的一部分,如下所示:
failcount = 0
done = False
while done == False:
try:
result = subprocess.check_output(program)
done = True
except subprocess.CalledProcessError as e:
failcount += 1
logwrite('logfile.txt', 'Failed. Counter = {0}\nError message: {1}\n-'.format(failcount, e.returncode))
if failcount == 20:
print 'It failed 20 times, aborting...'
quit()
这意味着要从命令行运行“program”。 “program”是一个大型计算化学软件包,有时会失败,所以我在这里循环运行它。如果它失败20次,那么我的python脚本终止。这很好用,它可以完成预期的工作。但是,我的问题是我的化学包每次尝试需要大约三个小时,我想要监视它。
如果我手动从命令行运行它,我可以简单地执行“program> logfile”,然后将日志文件拖尾以查看它。但是看起来你不能在python中做点什么:
subprocess.check_output(['program', '>', 'logfile'])
有没有办法让python打印出subprocess.check_output的内容,因为它正在被填充?我认为subprocess.check_output只包含stdout中的内容。我能以某种方式在python和管道之间克隆它吗?
可能的解决方法:我创建了一个名为run_program.sh的bash脚本,它只执行程序>我上面列出的logfile,然后我使用python的子进程来执行run_program.sh。这样我可以根据需要进行监视,但现在程序的输出是在一个文件中,而不是在python中,所以我必须让python读取一个大的日志文件,并在需要时捕获错误消息,所以我更愿意,如果我能避免这样的事情。
答案 0 :(得分:2)
您可以使用subprocess.Popen
,而不是使用subprocess.check_output
。此对象表示您的子进程,并具有您可以读取的stdout和stderr属性。如果您的子进程仅使用stdout,则可以在循环中调用Popen.stdout.readline()
。但是,如果子进程写入其他管道,则可能会遇到死锁(有关详细信息,请参阅文档)。在这种情况下,我建议http://stefaanlippens.net/python-asynchronous-subprocess-pipe-reading/中描述的consume
函数,它可以安全地让你在从子进程输出时逐行打印stdout和stderr。
或者,如果您将subprocess.check_output(['program', '>', 'logfile'])
传递给shell=True
函数,则使用check_output
的方法应该有效。 >
是一个shell指令,如果将其作为独立命令运行,则无法识别。
编辑:上面的内容不会返回Python程序的任何输出。相反,subprocess.check_output('program | tee logfile', shell=True)
。
如果使用shell = True,请注意您可以完全控制check_output
的参数。为了安全起见,永远不要允许任何用户或网络输入传递给shell。有关原因,请参阅this warning。