示例代码:
import subprocess
proc = subprocess.Popen(["/path/to/your/script"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(proc.stdout.readline, b''):
print(line.decode(), end='')
proc.stdout.close()
proc.wait()
这段代码使用subproceess.Popen
启动一个Shell进程来执行你的script。
shell=True
表示通过操作系统的Shell来执行命令;
stdout=subprocess.PIPE
表示将标准输出重定向到管道中,以便下一步处理,尽管示例中并没有下一步处理;
stderr=subprocess.STDOUT
表示将标准错误输出与标准输出合并;
iter
行语句使用迭代器逐行读取进程的标准输出,其中的b''
表示空字节,iter()
会持续读取,直到遇见空字节停止。
proc.stdout.close()
关闭标准输出管道,表示标准输出读取完毕。
proc.wait()
等待进程完成,并获取返回码。
如果你通过subprocess执行的脚本是某些易报错的程序,且在输出中会给出process id,那么你可以将这些pid捕获,然后再通过一个subprocess.run进程去执行kill它的命令,避免出错的程序干扰后面程序的自动执行;如果你的程序容易卡住,那么你可以使用signal模块设置一个定时器,结合try-except
语句进行超时报警,并做处理。例如:
import subprocess
import signal
def handler():
raise Exception("TIME UP!")
# 将信号处理函数handler与SIGALRM信号绑定,遇到SIGALRM信号时调用handler,也就是引发一个Exception
signal.signal(signal.SIGALRM, handler)
try:
signal.alarm(100) # 开始计时100s
try:
proc = subprocess.Popen(["/path/to/your/script"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pid_list = []
for line in iter(proc.stdout.readline, b''):
print(line.decode(), end='')
if "Process Id" in line.decode()
pid = pid_line.split(":")
pid = pid[1].strip()
pid_list.append(pid) # 获取涉及到的所有pid
proc.stdout.close()
proc.wait()
except:
try:
for pid in pid_list:
cmd = "kill -9" + pid
subprocess.run(cmd, shell=True) # 出错了之后把涉及到的进程都关掉
except:
pass # 关不掉就算了
signal.alarm(0)
except: # 超时发送SIGALRM信号,引发Exception,进入下面的代码分支
... # 处理超时情况的代码
上面这段代码总共嵌套了三层try-except
语句。
第一层用来处理程序卡住的问题,也就是配合signal的计时器,在超时是引发一个Exception,进入except分支进行超时处理;
第二层用来处理程序出错的问题,在try
中记录下所有涉及到的pid,如果报错,进入except
进行kill操作;
第三层用来处理kill失败的情况,如果kill不成功就算了,当然也可以进行别的处理(一个充满故事的try-except
)