如何正确处理subprocess.Popen输出的字符表示以提取CPU负载信息
如何正确处理subprocess.Popen输出的字符表示以提取CPU负载信息
Hey there! Let's break down what's going wrong with your code and fix it to properly extract CPU load (plus add CPU temperature reading) from your Raspberry Pi.
为什么字符串长度是387而不是预期的~50?
核心问题在于top命令默认会输出ANSI转义码(用于文本颜色、格式等终端渲染效果)。这些代码在打印时是不可见的,但会被包含在输出字符串中——这就是为什么你的TempCpu长度远超预期,还会打乱id字段的索引位置。
针对性修复方案
我们一步步来解决问题,同时优化代码的健壮性:
1. 关闭top的格式化输出
使用top的-b(batch模式)参数可以禁用所有ANSI格式代码,输出纯文本内容,完美适配脚本处理。修改后的命令应为:
top -b -n 1 | grep "%Cpu"
2. 更可靠的数值提取方式
避免使用硬编码的字符串索引(比如k-6:k),这种方式很容易因为输出格式微调而失效。改用字符串分割或正则表达式来提取目标值会更稳定。
3. 树莓派CPU温度读取
树莓派的CPU温度不需要通过top获取,直接读取系统文件/sys/class/thermal/thermal_zone0/temp即可(数值单位是毫摄氏度,除以1000转换为摄氏度)。
修复后的完整代码
这里用更现代的subprocess.run替代Popen(更简洁易用),同时加入远程SSH执行逻辑(如果你是在其他机器上运行脚本,需要连接树莓派):
#!/usr/bin/env python import subprocess answers = "" ips = ["192.168.70.13"] ip_names = ["xxx"] ssh_user = "pi" # 替换为你的树莓派用户名(默认是pi) for ip, name in zip(ips, ip_names): # -------------------------- # 1. 获取CPU负载 # -------------------------- # 远程执行(SSH到树莓派) cpu_cmd = f"ssh {ssh_user}@{ip} 'top -b -n 1 | grep %Cpu'" # 如果直接在树莓派上运行脚本,替换为下面的本地命令: # cpu_cmd = "top -b -n 1 | grep %Cpu" cpu_result = subprocess.run( cpu_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True # 自动将输出解码为字符串,无需手动调用decode() ) # 命令执行错误处理 if cpu_result.returncode != 0: print(f"获取{name}的CPU负载失败: {cpu_result.stderr.strip()}") continue cpu_output = cpu_result.stdout.strip() # 提取空闲CPU百分比和已用CPU百分比 idle_cpu = None for part in cpu_output.split(','): if 'id' in part: idle_cpu = part.strip().split()[0] used_cpu = 100.0 - float(idle_cpu) break # -------------------------- # 2. 获取CPU温度 # -------------------------- # 远程执行(SSH到树莓派) temp_cmd = f"ssh {ssh_user}@{ip} 'cat /sys/class/thermal/thermal_zone0/temp'" # 本地执行替换为: # temp_cmd = "cat /sys/class/thermal/thermal_zone0/temp" temp_result = subprocess.run( temp_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True ) cpu_temp = "N/A" if temp_result.returncode == 0: temp_millideg = temp_result.stdout.strip() cpu_temp = f"{float(temp_millideg)/1000:.1f} °C" # 格式化结果并输出 result_line = f"{name}: 已用CPU = {used_cpu:.1f}%, 空闲CPU = {idle_cpu}%, 温度 = {cpu_temp}" print(result_line) answers += result_line + "\n" print("\n最终汇总结果:\n" + answers)
关键改动说明
- Batch模式:
-b参数彻底解决了隐藏转义码的问题,输出字符串长度会和你看到的一致。 subprocess.run: 比Popen更简洁,text=True自动完成解码,省去手动处理字节串的麻烦。- 健壮的数值提取: 通过分割字符串查找
id字段,避免了硬编码索引的脆弱性。 - 错误处理: 新增命令执行失败的判断,比如SSH连接失败、文件不存在等情况。
- 远程执行支持: 加入SSH命令,如果你在其他机器上运行脚本,只需替换用户名即可连接树莓派。
预期输出
修复后你会看到类似如下的清晰结果:
xxx: 已用CPU = 0.0%, 空闲CPU = 100.0%, 温度 = 43.2 °C 最终汇总结果: xxx: 已用CPU = 0.0%, 空闲CPU = 100.0%, 温度 = 43.2 °C
内容来源于stack exchange
相关产品推荐
相关产品推荐

