You need to enable JavaScript to run this app. Flask执行Shell脚本时,如何将实时控制台日志输出到index.html模板
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 22:36:03