如何捕获subprocess输出?树莓派Discord Bot温度查询及命令执行报错求助
让我一步步帮你排查这两段代码的问题,以及怎么正确获取命令输出:
第一段代码的核心问题
你用subprocess.call()来执行命令,但这个函数的返回值是命令的退出状态码(0表示执行成功,非0表示失败),根本不是命令的输出内容。这就是为什么Bot会输出Your RPI3 temp is currently 0——因为vcgencmd measure_temp执行成功,返回了状态码0。
另外补充一点:你写的命令字符串"vcgencmdmeasure_temp"少了空格,正确格式应该是"vcgencmd measure_temp",不过即使命令写对,call()也拿不到输出结果。
第二段代码的报错原因
报错里提到命令'vcgencmdmeasure_temp'返回非零状态码12,这说明系统找不到这个命令。问题出在你处理输入参数的方式:
mesg = ''.join(args)
当你输入vcgencmd measure_temp时,args会被拆成('vcgencmd', 'measure_temp'),用空字符串join之后就变成了没有空格的vcgencmdmeasure_temp,系统自然找不到这个不存在的命令。
另外,subprocess.check_output()如果命令执行失败(退出码非0)会直接抛出CalledProcessError异常,你的代码没有捕获这个异常,所以会触发Discord的CommandInvokeError。
修正方案
1. 修复温度查询命令
用subprocess.check_output()来获取命令输出,同时处理输出内容,还要加异常捕获避免Bot崩溃:
@bot.command(pass_context=True) async def vcgencmdmeasure_temp(ctx): if ctx.message.author.id == "412372079242117123": await bot.say("OK....") try: # 获取命令输出,universal_newlines=True让返回值是字符串而非字节 temp_result = subprocess.check_output("vcgencmd measure_temp", shell=True, universal_newlines=True) # 提取温度值(原始输出格式是'temp=XX.X°C\n') temp_value = temp_result.strip().split('=')[1] await bot.say(f"Your RPI3 temp is currently: {temp_value}") except subprocess.CalledProcessError as e: await bot.say(f"Failed to get temperature: {str(e)}") except Exception as e: await bot.say(f"Unexpected error: {str(e)}") else: await bot.say("Error user lacks perms(only bot owner can run this)")
2. 修复任意命令执行功能
首先要正确拼接用户输入的命令(用空格join参数),然后捕获异常避免Bot崩溃:
@bot.command(pass_context=True) async def rpicmd(ctx, *args): if ctx.message.author.id == "412372079242117123": # 用空格拼接参数,保留命令的正确格式 cmd = ' '.join(args) try: # 同时捕获stderr输出,避免错误信息丢失 command_output = subprocess.check_output( cmd, shell=True, universal_newlines=True, stderr=subprocess.STDOUT ) await bot.say(command_output) except subprocess.CalledProcessError as e: await bot.say(f"Command failed with exit code {e.returncode}:\n{e.output}") except Exception as e: await bot.say(f"Error executing command: {str(e)}") else: await bot.say("No noob")
或者更优雅的方式,用*, cmd来直接接收完整的命令字符串(不需要手动join):
@bot.command(pass_context=True) async def rpicmd(ctx, *, cmd): if ctx.message.author.id == "412372079242117123": try: command_output = subprocess.check_output( cmd, shell=True, universal_newlines=True, stderr=subprocess.STDOUT ) await bot.say(command_output) except subprocess.CalledProcessError as e: await bot.say(f"Command failed with exit code {e.returncode}:\n{e.output}") except Exception as e: await bot.say(f"Error executing command: {str(e)}") else: await bot.say("No noob")
这样用户输入rpicmd vcgencmd measure_temp时,cmd会直接拿到完整的vcgencmd measure_temp字符串,不会出现拼接错误。
内容的提问来源于stack exchange,提问作者botbotbotty

