Python subprocess顺序执行配置脚本获取PID及返回码异常问题求助
问题解答
修正后完整代码
#! /usr/bin/python3 import configparser import argparse as ap import subprocess import sys import shlex import os import signal # 存储运行中的子进程对象,方便stop时调用 running_procs = [] def file_reader(): configParser = configparser.ConfigParser() configParser.read('config.ini') # 按配置文件顺序返回所有命令行,不需要反转字典 cmd_list = [] for section in configParser.sections(): # 按path1、path2、path3的顺序拿命令 for _, cmd in sorted(configParser.items(section), key=lambda x: x[0]): cmd_list.append(cmd) return cmd_list def kill_process(): global running_procs for proc in running_procs: try: if proc.poll() is None: # 进程还在运行 proc.kill() print(f"已杀死进程PID: {proc.pid}") except Exception as e: print(f"杀死进程PID {proc.pid}失败: {str(e)}") running_procs.clear() def main(): cmd_list = file_reader() parser = ap.ArgumentParser() parser.add_argument('-s', '--start', help='start script', action='store_true') parser.add_argument('-q', '--stop', help='stop script', action='store_true') args = parser.parse_args() if args.start and args.stop: print("error: 不能同时指定start和stop参数") sys.exit(1) elif args.start: for idx, cmd in enumerate(cmd_list, 1): print(f"正在执行第{idx}条命令: {cmd}") try: # 拆分命令为参数列表,关闭shell更安全,避免参数解析错误 cmd_args = shlex.split(cmd) # 用Popen启动进程,可获取PID proc = subprocess.Popen(cmd_args, close_fds=True) running_procs.append(proc) print(f"进程启动成功,PID: {proc.pid}") # 等待进程结束,设置超时时间(单位秒,可自行调整),超时会抛出TimeoutExpired异常 return_code = proc.wait(timeout=3600) if return_code != 0: if return_code < 0: print(f"进程PID {proc.pid} 被信号杀死,信号编号: {-return_code}") else: print(f"进程PID {proc.pid} 执行结束,返回码: {return_code}") # 如果需要某条命令失败就终止后续执行,打开下面的注释 # kill_process() # sys.exit(return_code) else: print(f"进程PID {proc.pid} 执行成功,返回码0") except subprocess.TimeoutExpired: print(f"进程PID {proc.pid} 执行超时,强制杀死") proc.kill() kill_process() sys.exit(1) except Exception as e: print(f"命令执行出错: {str(e)}") kill_process() sys.exit(1) print("\n所有命令执行完成") sys.exit(0) elif args.stop: kill_process() sys.exit(0) if __name__ == '__main__': try: main() except KeyboardInterrupt: kill_process() exit()
问题逐一说明
- 问题1、2(顺序执行+获取PID)解决:
原代码使用的subprocess.call是阻塞接口,只会返回进程退出码,无法获取进程PID。改用subprocess.Popen启动进程,可直接通过Popen.pid属性拿到进程ID。启动每个进程后调用wait()方法等待当前进程执行完成再启动下一个,即可实现按配置顺序逐个运行。如果进程运行卡住,可通过wait(timeout=xxx)设置超时时间,超时后直接调用proc.kill()杀死对应进程,也可以通过存储的PID手动执行kill操作。 - 问题3(返回码始终为1)解决:
该问题由两处错误导致:- 传参逻辑错误:
subprocess.call([k], shell=True)的写法中,开启shell=True时如果传入列表,只会将列表第一个元素作为命令执行,后续元素会被当作shell的参数而非命令的参数,你配置里的带参数的长命令根本没有正确执行,自然返回非0的错误码。修正方案是用shlex.split()将完整命令字符串拆分成参数列表,关闭shell=True,既避免参数解析错误,也更安全。 - 字典反转逻辑错误:原代码将配置的path到命令的字典反转为命令到path的字典,Python3.7之前的版本字典默认不保留插入顺序,会导致命令执行顺序和配置顺序不一致,甚至出现命令匹配错误的问题,直接按配置的key排序读取命令即可,无需反转字典。
- 传参逻辑错误:
内容的提问来源于stack exchange,提问作者Asad Javed
相关产品推荐
相关产品推荐

