Flask调用subprocess执行脚本时如何获取其衍生子进程的输出
问题根因
你的猜测不成立,subprocess.run()为阻塞调用,会等待被启动的进程完全执行结束后才会返回结果,不存在父进程提前终止的问题。你无法获取嵌套子进程输出的核心原因是:example.py中将ls -l的输出捕获到了result变量中,但没有将该内容输出到自身的标准输出流,因此app.py捕获的example.py的标准输出内容为空。
解决方案
下面给出三种不同场景下的解决方式:
方案1:修改被调用脚本,主动打印输出
如果可以调整用户提交的脚本写法,直接将捕获的结果打印到标准输出即可,修改后的example.py代码如下:
import subprocess result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8') # 将捕获的输出打印到标准输出,父进程即可捕获该内容 print(result.stdout)
此时app.py中result.stdout.decode('utf-8')即可正常获取到ls命令的输出。
方案2:子进程输出直接透传
不需要捕获嵌套子进程的输出做额外处理的话,可以让嵌套子进程直接继承父进程的标准输出流,无需手动打印:
import subprocess # 不指定stdout参数,默认继承当前进程的标准输出,内容会直接打到example.py的stdout中 subprocess.run(['ls', '-l'])
方案3:无需修改用户脚本,动态加载获取输出
如果不能修改用户提交的脚本,可以在app.py中用动态加载模块的方式直接读取脚本内的变量:
import sys import importlib.util @app.route('/scripts/<script_name>') def exec_script(script_name): script_path = os.path.join(app.config['SCRIPT_FOLDER'], script_name) if not os.path.isfile(script_path): return "脚本不存在", 404 # 动态加载用户脚本 spec = importlib.util.spec_from_file_location("user_script", script_path) user_script = importlib.util.module_from_spec(spec) sys.modules["user_script"] = user_script spec.loader.exec_module(user_script) # 直接读取脚本内的result变量内容 output = user_script.result.stdout.decode('utf-8') # 组装HTML返回 return f"<html><body><pre>{output}</pre></body></html>"
注意事项
- 你当前的实现存在极高的安全风险,允许执行任意Python脚本会直接导致服务器权限泄露,生产环境禁止直接使用该逻辑。
- 如果需要同时捕获错误输出,可以给
subprocess.run添加stderr=subprocess.STDOUT参数,将错误流合并到标准输出流中。 - 执行命令时指定
encoding='utf-8'参数,可以省去后续手动decode的步骤,也能避免部分中文乱码问题。
内容的提问来源于stack exchange,提问作者Mazzola
相关产品推荐
相关产品推荐

