Python指定路径执行Shell命令烧录固件找不到hex文件求助
问题根因
你设置的cwd参数未生效的核心原因是Windows路径字符串转义错误:cwd="C:\iot_flasher"中的\是Python字符串的转义符,解析后不会指向你预期的C:\iot_flasher目录,导致子进程工作目录根本没切换成功,自然找不到同目录下的slim.hex文件。
除此之外你的代码还有几个影响稳定性的隐患:
- 硬编码绝对路径兼容性极差,工具迁移位置、同事电脑目录结构不一致时会直接失效
- 用stderr是否有输出判断执行结果逻辑错误:多数命令行工具正常运行时也会向stderr输出提示信息,而部分异常场景下程序返回错误码但不输出stderr,会导致状态判断完全错乱
- 开启
shell=True存在不必要的命令注入风险,内部工具场景也没必要保留该配置 - 逐行读取stdout/stderr在部分场景下会因为管道缓冲阻塞,导致界面卡死
修复方案
1. 紧急修复(最小改动)
把cwd的路径写法改成以下任意一种即可解决当前找不到文件的问题:
- 加原生字符串标记禁止转义:
cwd=r"C:\iot_flasher" - 用Windows兼容的正斜杠写路径:
cwd="C:/iot_flasher" - 双写反斜杠做转义:
cwd="C:\\iot_flasher"
2. 稳妥优化版(推荐)
不要硬编码路径,基于脚本自身位置定位固件目录,同时修正执行逻辑的问题,适配分发给同事使用的场景,参考实现如下:
import os from subprocess import Popen, PIPE # 获取当前脚本/程序所在的绝对目录,不管从哪个路径启动都能准确定位 SCRIPT_BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 固件目录固定为脚本同级的iot_flasher文件夹,也可以根据你的实际存放位置调整 FIRMWARE_FOLDER = os.path.join(SCRIPT_BASE_DIR, "iot_flasher") # 提前拼接固件文件的绝对路径,完全不依赖工作目录查找文件 TARGET_HEX_PATH = os.path.join(FIRMWARE_FOLDER, "slim.hex") def run_command(cmd_args, work_dir=None): # 关闭shell,用列表传参避免转义问题,更安全稳定 return Popen( cmd_args, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=False, cwd=work_dir ) def btn_click(): output_box.delete("1.0", "end") if iot_model.get() == "V3x Catacomb": if mode_selection.get() == 0: cmd = ["nrfjprog", "-d"] run_dir = None elif mode_selection.get() == 1: cmd = ["nrfjprog", "--eraseall"] run_dir = None elif mode_selection.get() == 2: # 烧录固件前先校验文件是否存在,提前给用户明确提示 if not os.path.exists(TARGET_HEX_PATH): output_box.insert(END, f"错误:未找到固件文件,预期存放路径:{TARGET_HEX_PATH}") output_box.configure(background="red") return cmd = ["nrfjprog", "--program", TARGET_HEX_PATH, "--chiperase", "--reset"] run_dir = FIRMWARE_FOLDER with run_command(cmd, work_dir=run_dir) as proc: # 一次性读取全量输出,避免管道缓冲阻塞界面 stdout_content, stderr_content = proc.communicate() if stdout_content: output_box.insert(END, stdout_content) if stderr_content: output_box.insert(END, stderr_content) # 用进程退出码判断执行结果,0为成功,非0为失败,是命令行程序的通用标准 output_box.configure(background="green" if proc.returncode == 0 else "red")
额外注意事项
- 如果你后续用PyInstaller等工具把脚本打包成exe分发给同事,需要把
slim.hex、nrfjprog.exe等依赖文件一起打包,同时调整SCRIPT_BASE_DIR的获取逻辑适配打包后的临时运行路径 - 建议提前在工具启动时检查
nrfjprog是否可用,避免同事因为没加环境变量跑不起来,也可以直接把nrfjprog.exe放在工具目录下,拼绝对路径调用 - 如果需要实时输出命令执行日志而不是等执行完一次性显示,可以开单独的线程读管道,不要在tkinter的主线程里做阻塞操作,不然界面会无响应
内容的提问来源于stack exchange,提问作者gusfragger
相关产品推荐
相关产品推荐

