如何通过Flask Python API运行并终止Linux命令?
实现stop_cmd接口终止运行的命令(可行)
你的需求完全可以实现,核心问题是原代码中使用subprocess.call无法跟踪子进程,且没有保存进程引用。下面是修改后的完整代码,附带关键说明:
修改后的代码
from flask import Flask, jsonify, request from threading import Thread from subprocess import Popen import os import signal app = Flask(__name__) running_process = None # 全局变量跟踪运行的子进程 def RunCmd(): global running_process # 使用Popen启动命令,开启新进程组避免孤儿进程 running_process = Popen( 'while true; do echo "hello"; sleep 2s; done', shell=True, start_new_session=True ) running_process.wait() # 阻塞等待进程结束 @app.route('/run_cmd', methods=['GET']) def run_cmd(): global running_process # 检查是否已有命令在运行 if running_process is not None and running_process.poll() is None: return jsonify({ "status": "error", "message": "已有命令在运行,无法重复启动" }), 400 Thread(target=RunCmd).start() return jsonify({"status": "ok"}), 200 @app.route('/stop_cmd', methods=['GET']) def stop_cmd(): global running_process # 检查是否有正在运行的命令 if running_process is None or running_process.poll() is not None: return jsonify({ "status": "error", "message": "没有正在运行的命令" }), 400 # 杀掉整个进程组(避免shell子进程变成孤儿进程继续运行) try: os.killpg(os.getpgid(running_process.pid), signal.SIGTERM) running_process.wait() running_process = None return jsonify({ "status": "ok", "message": "命令已成功终止" }), 200 except Exception as e: running_process = None return jsonify({ "status": "error", "message": f"终止命令失败: {str(e)}" }), 500 if __name__ == '__main__': app.run(debug=True)
关键说明
替换
subprocess.call为Popen:call是阻塞式调用,会等待命令结束才返回,且无法获取进程句柄;Popen启动子进程后立即返回进程对象,允许后续对进程进行终止、状态查询等操作。
进程组处理:
- 由于使用
shell=True,实际执行循环命令的是shell的子进程;若仅终止shell进程,子进程会变成孤儿进程继续运行。 - 通过
start_new_session=True创建新的进程组,再用os.killpg杀掉整个进程组,确保所有相关进程都被终止。
- 由于使用
状态检查与全局变量:
- 用全局变量
running_process跟踪当前运行的进程,通过poll()方法判断进程是否存活(返回None表示正在运行); - 接口中增加状态检查,避免重复启动命令或终止不存在的进程。
- 用全局变量
部署注意事项:
- 如果使用多worker模式部署Flask(如Gunicorn多进程),全局变量无法在worker间共享,此时需要用外部存储(如Redis)保存进程ID和状态。
内容的提问来源于stack exchange,提问作者S Andrew
相关产品推荐
相关产品推荐

