如何通过Flask逐行读取shell输出并实时流式展示在HTML页面
Flask实现Shell命令输出实时流式推送到浏览器解决方案
原代码存在两个核心问题:
- 循环内直接执行
return语句,第一次拿到输出行就终止了函数执行,因此仅能返回第一行内容 - 普通
render_template是一次性渲染完整页面后返回,不支持分段输出,无法实现实时推送
可直接运行的实现代码
基于Flask原生流式响应实现,无需额外依赖:
from flask import Flask, Response import subprocess app = Flask(__name__) @app.route("/test", methods=['POST','GET']) def ping(): # 生成器函数:分段输出内容 def generate(): # 先输出HTML基础结构 yield """ <!DOCTYPE html> <html> <head> <title>命令实时输出</title> <style> .log-area { background: #1e1e1e; color: #4ec9b0; padding: 20px; font-family: Consolas, monospace; line-height: 1.5; } </style> </head> <body> <h3>命令执行实时输出</h3> <div class="log-area"> """ # 启动子进程执行shell命令 proc = subprocess.Popen( ['ping -c 10 8.8.8.8'], # 可替换为任意Linux Shell命令 shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # 合并错误输出到标准输出 text=True, # 直接返回字符串无需手动decode bufsize=1 # 启用行缓冲 ) # 逐行读取子进程输出,实时返回 for line in iter(proc.stdout.readline, ''): # 转义HTML特殊字符避免解析异常,同时替换换行符为HTML换行标签 safe_line = line.replace('<', '<').replace('>', '>').replace('\n', '<br>') yield safe_line # 输出HTML收尾结构 yield """ </div> </body> </html> """ # 返回流式响应,指定MIME类型为HTML return Response(generate(), mimetype='text/html') if __name__=="__main__": app.run(debug=True, port=5000)
注意事项
- 命令注入风险:生产环境禁止直接执行用户传入的任意shell命令,所有可执行命令、参数必须做严格白名校验
- 缓冲区适配:部分Linux命令默认使用全缓冲,会导致输出攒到一定大小才返回,可在命令前加
stdbuf -oL强制行缓冲,示例:['stdbuf -oL your_custom_command'] - 进程回收:长时间运行的命令需要添加超时、主动杀死子进程的逻辑,避免产生僵尸进程占用系统资源
- 模板复用:如果要嵌入现有
home.html页面,可使用Server-Sent Events(SSE)方案:后端单独提供text/event-stream类型的流式接口,前端通过EventSource监听接口数据,动态追加到页面指定容器即可
内容的提问来源于stack exchange,提问作者shreesh
相关产品推荐
相关产品推荐

