python调用外部程序:subprocess的一个应用实例

August 2018 · 1 minute read

这次我们要解决的问题是这样的:

有一个算法模块或者模型本身是由其他语言编写并且编译好的二进制可执行程序, 我们现在需要用 python 调用执行该程序,并且自动获知该程序的执行状态,包括可能输出的错误信息。

如果该程序遇到错误可以直接输出错误信息并且退出,这种情况显然还是非常容易处理的, 我们只需要将其输出的错误信息重定向到一个日志文件中即可,os.system() 足以解决问题:

import os

if os.name == 'posix':
    os.system('nohup ./main.exe > log 2>&1 &')
if os.name == 'nt':
    os.system('main.exe 1>log 2>&1')

这次的情况是,该程序遇到错误时首先输出了一些错误信息提示,说必须手动按下 <Enter> 键才能退出。 用 os.system() 显然不方便获取错误信息内容去判断是否要额外执行其他操作。 这时用 subprocess.Popen() 就好了:

import os
import subprocess

# 比如应用程序所在路径是 bin_dir
os.chdir(bin_dir)

if os.name == 'posix':
    p = subprocess.Popen('./main.exe', 
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
if os.name == 'nt':
    p = subprocess.Popen('main.exe', 
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
# 一行一行读取 stdout,因为当进程 p 没有结束时,stdout 没有文件结束符,所以不能被 read()
stdout = ''
while p.poll() is None:
    line = p.stdout.readline()
    stdout += line
    if '<Enter>' in line:
        subprocess.Popen.kill(p)  # 读到提示按 '<Enter>' 键的信息时,结束程序,退出
        break
else:
    stdout = p.stdout.read()
# print(stdout)
# 可以写出 stdout 到一个日志文件中
with open('log', 'w') as f:
    f.write(stdout)

好了,就到这里。