系统重启后自动运行,测试脚本亲测可用
1. 为什么需要开机自启?——从实际需求出发
你有没有遇到过这样的情况:树莓派部署在仓库角落做温湿度监控,半夜断电重启后,数据采集脚本没起来,整整八小时的数据全丢了;或者你在工控机上跑着一个图像识别服务,每次重启都要手动SSH进去敲几行命令,既耽误事又容易忘?
这不是个别现象。在嵌入式设备、边缘计算节点、无人值守服务器这些真实场景里,“系统一启动就干活”不是锦上添花的功能,而是刚需。
这个镜像叫“测试开机启动脚本”,名字很朴实,但它解决的是一个非常具体、高频、且容易踩坑的问题:让一段简单脚本,在系统完成初始化后,稳稳当当地跑起来,并留下可验证的痕迹。
它不追求复杂服务管理,也不堆砌systemd高级特性,而是聚焦一件事:你写好一个.sh文件,放进指定位置,重启一次,就能看到效果。下面所有内容,都围绕这个目标展开。
2. 三种主流方案实测对比:哪个最靠谱?
我们不是罗列理论,而是把三种常见方案——rc.local、systemd用户服务、systemd系统服务——全部在Ubuntu 22.04(LTS)和Raspberry Pi OS(Bookworm)上实测了一遍。结果很明确:对纯脚本类任务,rc.local依然是最轻量、最直观、最容易排查的方案。
2.1 rc.local方案:小白友好度最高,重启即见效
/etc/rc.local是Linux世界里的“老朋友”。它的逻辑极其简单:系统启动流程走到最后阶段(网络已就绪、文件系统已挂载),就按顺序执行这个文件里的每一行命令。
它最大的优势是:所见即所得。你加一行date >> /tmp/boot.log,重启后打开/tmp/boot.log,立刻就能看到时间戳。没有抽象的服务单元、没有复杂的依赖声明、没有权限陷阱。
但要注意两个前提:
- 文件必须存在且有执行权限
rc-local.service必须被systemd正确识别并启用
我们用这个镜像做了完整验证:
# 1. 创建测试脚本(记录启动时间和主机名) sudo tee /usr/local/bin/boot-check.sh << 'EOF' #!/bin/bash echo "=== System Booted at $(date) ===" >> /var/log/boot-check.log echo "Hostname: $(hostname)" >> /var/log/boot-check.log echo "Uptime: $(uptime)" >> /var/log/boot-check.log echo "" >> /var/log/boot-check.log EOF sudo chmod +x /usr/local/bin/boot-check.sh# 2. 将其加入rc.local(注意末尾的&和exit 0) sudo tee -a /etc/rc.local << 'EOF' # Run our boot check script /usr/local/bin/boot-check.sh & exit 0 EOF # 3. 确保rc.local有执行权限 sudo chmod +x /etc/rc.local关键细节提醒:
/etc/rc.local文件末尾必须有exit 0,否则systemd会认为脚本执行失败而中断启动流程;
脚本调用后面加&是为了后台运行,避免阻塞整个启动过程;
日志路径选/var/log/而非/home/xxx/,因为此时用户家目录可能尚未挂载。
重启后,执行sudo tail -n 20 /var/log/boot-check.log,你会看到类似这样的输出:
=== System Booted at Mon Jun 10 14:22:37 CST 2024 === Hostname: raspberrypi Uptime: 14:22:37 up 0 min, 1 user, load average: 1.23, 0.45, 0.15这说明:脚本不仅运行了,而且是在系统完全就绪后才执行的。
2.2 systemd用户服务:适合个人桌面环境,但有登录依赖
~/.config/systemd/user/下的服务,只在特定用户登录图形界面或终端时才启动。这对开发机很合适——比如你希望每次登录GNOME就自动启动一个本地Web服务。
但对无头设备(headless device)来说,这是个硬伤。树莓派接显示器启动GUI?可以。但如果你用ssh远程连接,或者设备根本没接显示器,这个服务压根不会启动。
我们试过一个极简服务:
# ~/.config/systemd/user/boot-test.service [Unit] Description=Boot Test Script (User) [Service] Type=oneshot ExecStart=/usr/local/bin/boot-check.sh RemainAfterExit=yes [Install] WantedBy=default.target执行systemctl --user daemon-reload && systemctl --user enable boot-test.service后,发现:
- 图形界面登录后,日志正常生成;
- 仅通过SSH登录,日志不会生成;
- 重启后未登录任何桌面,日志依然为空。
结论:如果你的设备不需要用户交互,这个方案就不适用。
2.3 systemd系统服务:功能最强,但配置门槛略高
/etc/systemd/system/下的服务是真正的“系统级”,开机即启,不依赖用户登录。它能精确控制启动时机(比如“等网络就绪后再启动”)、失败重试策略、资源限制等。
但正因强大,也更易出错。一个常见的坑是:你的脚本依赖网络,但服务定义里没声明After=network.target,结果脚本执行时网络还没通,curl失败、wget超时。
我们为这个镜像编写了一个健壮的系统服务示例:
# /etc/systemd/system/boot-check.service [Unit] Description=Boot Check Script (System) After=multi-user.target network.target Wants=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/boot-check.sh RemainAfterExit=yes User=root StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target启用它:
sudo systemctl daemon-reload sudo systemctl enable boot-check.service sudo systemctl start boot-check.service这个方案确实可靠,但你会发现:要验证它是否生效,得查journal日志(sudo journalctl -u boot-check.service -n 20),而不是直接看一个文本文件。对只想快速确认“脚本动了没”的用户来说,多了一层间接性。
3. 镜像实操指南:三步完成,全程可验证
这个镜像的核心价值,就是把上面验证过的rc.local方案打包成开箱即用的体验。它不预装任何业务逻辑,只提供一套经过压力测试的启动框架,你只需填入自己的脚本。
3.1 镜像启动后的第一件事:检查基础环境
镜像启动后,先执行以下命令,确认关键组件就位:
# 检查rc.local是否存在且可执行 ls -l /etc/rc.local # 检查rc-local.service状态 systemctl status rc-local.service # 查看boot-check.log初始状态(应为空或有历史记录) sudo cat /var/log/boot-check.log 2>/dev/null | head -5如果rc-local.service显示inactive (dead),别慌,执行这条命令即可激活:
sudo systemctl enable --now rc-local.service3.2 替换你的脚本:两处修改,一处生效
镜像中已预置/usr/local/bin/boot-check.sh作为模板。你要做的,只是替换它的内容。
假设你想让设备启动时发送一条微信通知(用Server酱),操作如下:
# 1. 编辑脚本(用nano或vim) sudo nano /usr/local/bin/boot-check.sh将原有内容全部删掉,替换成:
#!/bin/bash # 发送微信通知(需提前注册Server酱,获取SCKEY) SCKEY="your_sckey_here" MESSAGE="【设备启动】$(hostname) 于 $(date) 重启成功" curl -X POST "https://sctapi.ftqq.com/${SCKEY}.send" \ --data-urlencode "title=系统通知" \ --data-urlencode "desp=${MESSAGE}" \ -s > /dev/null 2>&1 # 同时记录到本地日志,双重保障 echo "$(date): WeChat notification sent" >> /var/log/boot-check.log# 2. 保存后,给脚本加执行权限(虽然镜像已设,但养成习惯) sudo chmod +x /usr/local/bin/boot-check.sh # 3. 重启验证(或用systemctl restart rc-local.service模拟) sudo reboot重要提示:
如果你的脚本需要网络,请确保它放在/etc/rc.local中exit 0之前,并且不要在脚本里写sleep 10这种粗暴等待。systemd的rc-local.service本身已设置After=network.target,你只需专注业务逻辑。
3.3 验证与排错:五种常见问题及解法
| 问题现象 | 可能原因 | 快速诊断命令 | 解决方案 |
|---|---|---|---|
| 重启后日志文件完全没生成 | /etc/rc.local权限不对或缺少exit 0 | sudo ls -l /etc/rc.localsudo cat /etc/rc.local | tail -3 | sudo chmod +x /etc/rc.local确保末尾有 exit 0 |
| 日志有内容但时间是旧的 | rc-local.service未启用 | systemctl status rc-local.service | sudo systemctl enable --now rc-local.service |
| 脚本执行了但网络请求失败 | 网络未就绪就执行 | sudo journalctl -u rc-local.service -n 20 | 在脚本开头加until ping -c1 google.com; do sleep 2; done(慎用)或改用systemd服务并声明After=network.target |
日志里出现Permission denied | 脚本尝试写入受限目录 | sudo grep -i "permission" /var/log/boot-check.log | 改用/var/log/或/tmp/目录,或在脚本中加sudo(不推荐) |
| 重启卡在紫色屏幕 | rc.local中某条命令阻塞了启动 | 开机时按ESC键看终端输出 | 检查/etc/rc.local中是否有无&的前台命令,或移除可疑行 |
4. 进阶技巧:让自启脚本更聪明、更可靠
一个“能用”的脚本和一个“好用”的脚本,差距在于细节。这里分享几个经实战检验的技巧。
4.1 添加启动耗时统计,量化你的优化成果
在脚本开头和结尾分别记录时间,就能知道它到底花了多久:
#!/bin/bash START_TIME=$(date +%s.%N) # 你的核心逻辑在这里 echo "Doing real work..." >> /var/log/boot-check.log sleep 2 # 模拟耗时操作 END_TIME=$(date +%s.%N) ELAPSED=$(echo "$END_TIME - $START_TIME" | bc) echo "Script completed in ${ELAPSED}s" >> /var/log/boot-check.log这样,每次升级脚本后,你都能用数据说话:“优化后启动时间从3.2秒降到1.8秒”。
4.2 使用锁文件防止重复执行
某些脚本(如数据库初始化)绝不允许并发运行。加一个简单的锁机制:
LOCK_FILE="/tmp/boot-check.lock" if [ -f "$LOCK_FILE" ]; then echo "$(date): Script already running, exit." >> /var/log/boot-check.log exit 0 fi touch "$LOCK_FILE" # ... 主体逻辑 ... rm -f "$LOCK_FILE"4.3 自动清理旧日志,避免磁盘占满
长期运行的设备,日志会越积越多。在脚本末尾加一行:
# 保留最近7天的日志 find /var/log/boot-check.log* -mtime +7 -delete 2>/dev/null5. 总结:选择最适合你场景的方案
回到最初的问题:系统重启后,如何让脚本自动运行?
- 如果你追求“写完就跑,一秒验证”:用镜像自带的
rc.local方案。它不炫技,但足够可靠,90%的嵌入式和边缘场景都适用。 - 如果你的设备有图形界面,且脚本只服务于当前用户:
systemd用户服务是更现代的选择,资源隔离性更好。 - 如果你需要精细控制启动时机、失败策略、资源配额,且愿意投入学习成本:
systemd系统服务是终极答案,尤其适合生产服务器。
这个镜像的价值,不在于它有多复杂,而在于它把最朴素、最有效的方案,打磨到了“开箱即用”的程度。它省去了你查文档、试错、调试的数小时,把确定性交还给你。
现在,你只需要想清楚一件事:下次设备重启时,你最希望它第一件事做什么?把那件事写进/usr/local/bin/boot-check.sh,然后重启。剩下的,交给这个镜像。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。