Flask执行Shell脚本时,如何将实时控制台日志输出到index.html模板
实时脚本输出同步展示实现方案
核心问题定位
当前代码无法实现实时输出展示的根源是:使用的subprocess.call是完全阻塞式调用,会等Shell脚本全量执行完成才会返回控制权,全程无法捕获执行过程中的中间输出内容,必须换成带管道连接的逐行读取模式,配合Flask的流式响应实现边执行、边推送、边展示的效果。
后端Flask完整实现代码
import subprocess from flask import Flask, request, Response, render_template app = Flask(__name__) # 关闭模板缓存,确保流式内容实时推送到前端 app.config['TEMPLATES_AUTO_RELOAD'] = True def generate_log_stream(git_url): # 先渲染模板基础骨架,替换日志容器占位符 base_page = render_template('index.html') log_container_html = '<div id="log-output" style="white-space: pre-wrap; font-family: monospace; padding: 1rem; border: 1px solid #eee; border-radius: 4px;"></div>' page_shell = base_page.replace('<!-- LOG_CONTAINER -->', log_container_html) yield page_shell # 按顺序执行两个Shell脚本 script_list = ['installer_script1.sh', 'installer_script2.sh'] for script_path in script_list: # 启动子进程建立输出管道,逐行读取实时内容 proc = subprocess.Popen( ['sh', script_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # 合并报错流到标准输出,同步展示报错信息 text=True, bufsize=1, # 开启行缓冲,避免输出攒成大段一次性返回 env={"GIT_URL": git_url} # 把表单获取的git地址通过环境变量传给脚本 ) # 逐行读子进程输出,每读到一行就推一行到前端 for line in proc.stdout: # 生成极简JS片段,直接追加内容到日志容器 escaped_line = line.rstrip().replace('`', '\\`') yield f'<script>document.getElementById("log-output").innerText += `{escaped_line}\n`</script>' proc.wait() # 脚本执行完成后推送状态提示 yield f'<script>document.getElementById("log-output").innerText += "\n===== 脚本 {script_path} 执行完成,退出码:{proc.returncode} =====\n"</script>' @app.route('/result', methods=["POST"]) def process_html_input(): if request.method == "POST": git_url = request.form.get("giturl", "") # 返回流式响应,边执行脚本边推送内容 return Response(generate_log_stream(git_url), mimetype='text/html') # 非POST请求直接返回空白模板 return render_template("index.html") if __name__ == '__main__': # 开启多线程模式,避免单请求阻塞导致输出卡顿 app.run(debug=True, threaded=True)
index.html 模板代码
<html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>脚本执行日志</title> </head> <body> <h3>Shell 脚本实时执行日志</h3> <!-- LOG_CONTAINER --> </body> </html>
关键实现说明
- 核心能力替换:放弃无管道输出捕获能力的
subprocess.call,改用subprocess.Popen建立进程标准输出管道,逐行读取脚本执行过程中的实时输出内容 - 流畅输出配置:开启行缓冲模式,避免输出内容攒成大段才返回,脚本执行过程中每产生一行控制台输出,就会立刻同步到页面
- 无额外前端逻辑:不需要写轮询、WebSocket代码,每读到一行脚本输出,就生成一段极简JS片段推送到前端,直接把内容追加到日志展示容器
- 参数透传优化:原代码中从表单获取的
git_url参数没有传递给Shell脚本,现在通过环境变量把参数注入子进程,脚本内部可以直接通过$GIT_URL读取用户提交的仓库地址 - 服务稳定性配置:启动时开启多线程模式,避免单请求阻塞导致的页面无响应问题
内容的提问来源于stack exchange,提问作者Gissipi_453
相关产品推荐
相关产品推荐

