news 2026/2/17 12:33:09

有了这个脚本,再也不用担心设备重启后的配置丢失

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
有了这个脚本,再也不用担心设备重启后的配置丢失

有了这个脚本,再也不用担心设备重启后的配置丢失

1. 为什么重启后配置会“消失”?

你有没有遇到过这样的情况:
在树莓派、Orange Pi 或其他 ARM 开发板上,好不容易把 GPIO 引脚设成输出、把网络参数调好、把 USB 摄像头的权限配完,结果一重启——全没了。LED 不亮了,摄像头打不开,IP 地址又变回默认值。

这不是设备坏了,也不是你操作错了。
这是 Linux 启动机制在“按规矩办事”:它只加载内核和基础服务,不会主动记住你手动执行过的每一条命令。

比如你敲了这行:

echo "6" > /sys/class/gpio/export

系统确实把 GPIO6 导出了,但/sys是内存中的虚拟文件系统(sysfs),断电即清空。重启后,所有通过echo写入的配置都会归零。

再比如你改了/etc/network/interfaces,加了一条静态 IP,但忘了让网络服务在开机时自动启用——那配置文件虽在,服务却不启动,IP 还是 DHCP 获取的。

所以问题本质不是“配置丢了”,而是配置没被纳入启动流程
只要让这些操作变成“开机自动执行的任务”,一切就稳了。


2. 两种主流方案:init.d 和 systemd,选哪个?

Armbian 默认基于 Debian/Ubuntu,而现代 Debian 系统早已全面转向systemd作为 PID 1 进程(也就是系统第一个启动的程序)。你可以用这条命令确认:

ps -p 1 -o comm=

如果输出是systemd,那就说明:你的设备底层就是 systemd 驱动的。

但 Armbian 为了兼容老用户和旧教程,仍然支持传统的/etc/init.d/脚本方式。也就是说,你写一个gpio-init.sh放进/etc/init.d/,再用update-rc.d注册,它也能跑起来——只不过,systemd 会在背后悄悄把它包装成一个临时 service 来运行。

那么该选哪条路?我们直接说结论:

新项目、新脚本,一律推荐 systemd unit 方式
不建议为新需求再写 init.d 脚本(除非维护遗留系统)

原因很实在:

  • systemd 支持精确依赖控制(比如“等网络就绪后再运行我的脚本”)
  • 启动过程并行化,比 init.d 串行执行快得多
  • 日志统一归档,用journalctl -u myscript.service就能查全部输出
  • 错误自动捕获,失败时有明确状态提示,不像 init.d 脚本静默失败

下面我们就用一个真实可运行的案例,带你从零写出一个“开机自动恢复 GPIO 配置”的脚本,并确保它稳定可靠。


3. 动手实践:写一个真正可靠的开机启动脚本

3.1 明确目标与范围

我们要解决的不是“让 LED 亮起来”这个单一动作,而是构建一个可复用、可维护、可扩展的配置恢复机制。具体包括:

  • 自动导出指定 GPIO 引脚(6、7、8、9、10)
  • 设置方向(out/in)
  • 设置初始电平(高/低)
  • 兼容不同硬件平台(避免硬编码路径)
  • 出错时有日志可查,不卡死启动流程

提示:不要把所有配置都塞进一个脚本里。GPIO 初始化、网络配置、USB 设备权限,应分拆为独立 service,便于单独启停和调试。


3.2 编写核心脚本文件

我们把实际操作逻辑放在一个独立的 shell 脚本中,路径定为/usr/local/bin/device-init.sh(放在这里符合 FHS 标准,且不易被系统更新覆盖):

#!/bin/bash # device-init.sh —— 设备级初始化脚本 # 支持:GPIO 配置、USB 权限修复、自定义网络准备等 set -e # 任一命令失败即退出 LOG_FILE="/var/log/device-init.log" exec >> "$LOG_FILE" 2>&1 echo "[$(date)] ===== Starting device init =====" # --- GPIO 配置区 --- GPIO_LIST=(6 7 8 9 10) for pin in "${GPIO_LIST[@]}"; do if [ ! -d "/sys/class/gpio/gpio${pin}" ]; then echo "Exporting GPIO${pin}" echo "${pin}" > /sys/class/gpio/export 2>/dev/null || true sleep 0.1 fi done # 设置方向与初始值 echo "out" > /sys/class/gpio/gpio6/direction echo "in" > /sys/class/gpio/gpio7/direction echo "out" > /sys/class/gpio/gpio8/direction echo "out" > /sys/class/gpio/gpio9/direction echo "out" > /sys/class/gpio/gpio10/direction echo "1" > /sys/class/gpio/gpio6/value # 系统运行指示灯 echo "0" > /sys/class/gpio/gpio8/value # 默认关闭某功能引脚 echo "0" > /sys/class/gpio/gpio9/value echo "0" > /sys/class/gpio/gpio10/value # --- USB 设备权限修复(示例)--- if [ -c "/dev/video0" ]; then echo "Fixing video0 permissions" chmod 666 /dev/video0 fi echo "[$(date)] ===== Device init completed ====="

保存后赋予执行权限:

sudo chmod +x /usr/local/bin/device-init.sh

小技巧:脚本开头加set -e,确保任意一步失败就停止,避免半截配置引发异常;重定向日志到/var/log/,方便后续排查。


3.3 创建 systemd service 单元文件

接下来,告诉 systemd:“这个脚本,我要你在开机时自动运行”。

创建 service 文件:

sudo nano /etc/systemd/system/device-init.service

内容如下(注意注释已精简,生产环境建议保留):

[Unit] Description=Device initialization at boot Documentation=https://github.com/yourname/device-init After=multi-user.target Wants=multi-user.target [Service] Type=oneshot ExecStart=/usr/local/bin/device-init.sh RemainAfterExit=yes User=root StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target

关键点说明:

  • Type=oneshot:表示这是一个一次性执行的脚本,不是长期运行的服务
  • RemainAfterExit=yes:即使脚本执行完了,systemd 也认为该 service 处于“active”状态,方便依赖管理
  • User=root:必须以 root 权限运行,否则无法写入/sys/class/gpio/
  • StandardOutput=journal:所有echo输出都会进入 journal 日志,可用journalctl查看

启用并测试:

# 重新加载 systemd 配置 sudo systemctl daemon-reload # 启用开机自启 sudo systemctl enable device-init.service # 立即运行一次(不重启也可验证) sudo systemctl start device-init.service # 查看运行状态和日志 sudo systemctl status device-init.service sudo journalctl -u device-init.service -n 20 --no-pager

如果看到active (exited)和日志末尾有Device init completed,说明一切正常。


4. 常见问题与避坑指南

4.1 “脚本执行了,但 GPIO 没生效”

最常见原因是:脚本执行时机太早,GPIO 子系统还没就绪

比如/sys/class/gpio/目录在 kernel 加载 gpiochip 驱动后才出现。如果你的脚本在multi-user.target之前就运行,会因路径不存在而失败。

解决方案:在[Unit]中添加更精确的依赖:

After=sysinit.target Wants=sysinit.target

或者更稳妥地,加一行检测逻辑到脚本开头:

while [ ! -d "/sys/class/gpio" ]; do echo "Waiting for sysfs GPIO..." sleep 0.5 done

4.2 “重启后日志里有 Permission denied”

错误类似:

Failed to write '6' to '/sys/class/gpio/export': Permission denied

这是因为某些平台(如较新内核的 Armbian)默认禁用了 legacy sysfs GPIO 接口,转而使用libgpiod工具链。

解决方案有两个:

  • 短期兼容:在/boot/armbianEnv.txt中添加overlays=gpio-sysfs并重启(适用于旧版驱动)
  • 长期推荐:改用gpioset命令重写脚本(需安装gpiod包):
sudo apt install gpiod # 示例:设置 GPIO6 为高电平 gpioset $(gpiofind "GPIO6")=1

注意:gpiofind名称取决于设备树中定义的 label,不是所有板子都预设 label,此时仍需 fallback 到 sysfs。


4.3 “脚本运行了,但 LED 一闪就灭”

这往往是因为:脚本执行完后,其他服务(如某个用户空间程序或桌面环境)又把引脚重置了。

排查方法:

# 查看谁在操作 GPIO6 sudo lsof /sys/class/gpio/gpio6/* # 或监控写入行为 sudo auditctl -w /sys/class/gpio/gpio6/value -p w

长期解法:将关键引脚的控制权“锁定”,例如在 service 中加入:

# 防止被其他进程覆盖(仅限支持的内核) echo "6" > /sys/class/gpio/gpio6/active_low echo "1" > /sys/class/gpio/gpio6/direction

更彻底的方式是:把初始化逻辑封装进内核模块或设备树 overlay,但这已超出脚本范畴,属于深度定制。


5. 进阶建议:让配置真正“持久化”

上面的脚本解决了“开机执行”,但还有两个隐藏痛点:

  • 配置参数写死在脚本里,改个引脚号要编辑代码
  • 多台设备共用同一镜像,但 GPIO 用途各不相同

推荐做法:引入外部配置文件

新建/etc/device-init/config.yaml(需先安装yq工具):

gpio: - pin: 6 direction: out value: 1 label: "system_led" - pin: 8 direction: out value: 0 label: "relay_ctrl" usb: - device: "/dev/video0" mode: "0666"

然后修改device-init.sh,用yq读取配置动态执行。这样,不同设备只需替换 config.yaml,无需改动脚本本身。

提示:yq安装命令为sudo snap install yqsudo apt install python3-yaml && pip3 install yq(根据系统选择)。


6. 总结:一套脚本,三种保障

我们完成的不是一个“点灯脚本”,而是一套面向嵌入式场景的配置持久化工程实践

  • 第一层保障:机制可靠
    使用 systemd service 替代 init.d,获得依赖管理、日志追踪、状态反馈等原生能力。

  • 第二层保障:执行稳健
    脚本内置路径检测、错误捕获、日志记录,不因单点失败导致整机启动异常。

  • 第三层保障:维护友好
    配置与逻辑分离,支持多设备差异化部署,升级时只需替换配置文件。

最后提醒一句:

不要追求“一次写完,永远不用管”。真正的稳定性,来自清晰的结构、可验证的步骤、以及每次重启后都能快速定位问题的能力。

你现在拥有的,不只是一个脚本,而是一个可复制、可演进、可交付的嵌入式初始化范式。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/16 6:10:16

告别繁琐配置!用科哥镜像一键搭建OCR文字检测系统

告别繁琐配置!用科哥镜像一键搭建OCR文字检测系统 你是否还在为部署OCR系统焦头烂额?下载模型、安装依赖、配置环境、调试接口……一套流程走下来,半天时间没了,结果连第一张图片都还没识别出来。更别说还要处理CUDA版本冲突、Py…

作者头像 李华
网站建设 2026/2/11 20:25:03

你的青春正在消失?这款工具让QQ回忆永不褪色

你的青春正在消失?这款工具让QQ回忆永不褪色 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 发现数字记忆的守护者 当你在深夜滑动QQ空间,那些十年前的说说、毕…

作者头像 李华
网站建设 2026/2/14 10:50:42

SiameseUIE开源模型部署教程:从CSDN镜像拉取到生产环境Supervisor守护

SiameseUIE开源模型部署教程:从CSDN镜像拉取到生产环境Supervisor守护 你是不是也遇到过这样的问题:手头有一堆中文文本,想快速抽取出人名、地名、公司名、产品名,甚至评论里的“音质很好”“发货快”这类情感表达,但…

作者头像 李华
网站建设 2026/2/17 3:49:23

VL53L0X vs VL53L1X:飞行时间测距传感器的进化与选型指南

VL53L0X vs VL53L1X:飞行时间测距传感器的深度对比与实战选型指南 1. 飞行时间(ToF)技术基础与市场定位 激光测距技术在过去十年经历了从超声波、红外到ToF的迭代升级。STMicroelectronics推出的VL53L0X和VL53L1X代表了当前消费级ToF传感器的两个技术标杆。这两种…

作者头像 李华
网站建设 2026/2/9 3:48:39

用Qwen3-Embedding-0.6B提升搜索准确率,方法在这里

用Qwen3-Embedding-0.6B提升搜索准确率,方法在这里 你有没有遇到过这样的问题:用户搜“手机充电慢”,结果返回一堆“快充技术原理”“无线充电标准”的文章,真正想看的“如何解决iPhone充电变慢”却排在十几页之后?或者…

作者头像 李华
网站建设 2026/2/9 16:19:55

避免踩雷!微调Qwen2.5-7B时这些参数不能错

避免踩雷!微调Qwen2.5-7B时这些参数不能错 你是不是也试过:明明照着教程敲完命令,模型却训不起来、显存爆了、结果答非所问,甚至训练中途直接OOM?别急——这不是你代码写错了,大概率是几个关键参数悄悄“越…

作者头像 李华