You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 06:15:43