Pycord机器人:如何在调用者上下文运行多行Python脚本?
解决方案
一、用附件参数替代字符串参数解决多行输入问题
直接在斜杠命令里添加Attachment类型的参数,读取上传的文本文件内容作为脚本输入,同时做基础的文件格式校验:
import discord from discord.ext import commands bot = commands.Bot(command_prefix="!", intents=discord.Intents.all()) @bot.slash_command(name="dev", description="仅所有者可用的调试执行命令") @commands.is_owner() async def dev(ctx, script_file: discord.Attachment): # 只允许上传文本类文件 if not script_file.filename.endswith((".txt", ".py")): await ctx.respond("只能上传 .txt 或 .py 格式的文本文件") return # 读取文件内容 try: script_content = await script_file.read() script_content = script_content.decode("utf-8") except Exception as e: await ctx.respond(f"读取文件失败: {str(e)}") return # 调用执行脚本的逻辑 await run_script(ctx, script_content)
二、用exec执行多行脚本并捕获输出
eval只能处理单个表达式,多行脚本改用exec,同时通过重定向标准输出捕获print内容,还可以注入机器人上下文变量方便调试:
import io import sys from contextlib import redirect_stdout import ast async def run_script(ctx, script): # 注入常用变量到执行环境,方便调试时直接用 local_env = { "bot": ctx.bot, "ctx": ctx, "discord": discord, "commands": commands } output_buf = io.StringIO() result = None error_msg = None try: # 重定向stdout捕获print输出 with redirect_stdout(output_buf): exec(script, globals(), local_env) # 额外处理:如果脚本最后一行是表达式,获取其返回值 tree = ast.parse(script) if tree.body and isinstance(tree.body[-1], ast.Expr): last_expr = ast.unparse(tree.body[-1]) result = eval(last_expr, globals(), local_env) except Exception as e: error_msg = str(e) # 整理响应内容 response_parts = [] if output := output_buf.getvalue(): response_parts.append(f"输出内容:\n```\n{output}\n```") if result is not None: response_parts.append(f"返回结果:\n```\n{result}\n```") if error_msg: response_parts.append(f"执行错误:\n```\n{error_msg}\n```") if not response_parts: response_parts.append("脚本执行完成,无输出或返回值") # 发送响应(如果内容过长可以拆分或转成文件发送) await ctx.respond("\n".join(response_parts))
额外注意事项
- 务必严格限制命令权限,除了
@commands.is_owner(),也可以直接硬编码你的用户ID做双重校验,避免权限泄露 - 执行用户上传的脚本存在极高安全风险,仅在你完全可控的机器人环境中使用
- 如果脚本执行时间过长,会触发Discord的命令超时,可考虑用异步任务包装并设置超时时间
内容的提问来源于stack exchange,提问作者M1N3R
相关产品推荐
相关产品推荐

