如何验证开机脚本是否成功执行?教你几招
你写好了开机启动脚本,也按步骤加进了rc.local或systemd服务,但重启之后——啥也没发生?文件没生成、程序没运行、日志空空如也……这时候最抓狂的不是“怎么写”,而是“到底有没有跑起来”。
别急,这不是玄学,是可验证、可追踪、可定位的问题。本文不讲怎么写开机脚本(网上教程一搜一大把),专讲怎么确认它真·被执行了。从最基础的日志检查,到进程快照比对,再到自动回传验证,覆盖 Ubuntu/Debian 系统常见场景,所有方法都经过实测,无需额外安装复杂工具,小白也能照着操作。
全文聚焦一个核心目标:让你在重启后 2 分钟内,明确知道脚本是成功了、失败了,还是根本没触发。每种方法都附带具体命令、典型输出示例和关键判断依据,拒绝模糊描述。
1. 查看系统日志:最直接的“第一现场”
开机脚本是否执行,系统日志里往往留有最原始的痕迹。journalctl是现代 systemd 系统的默认日志工具,比翻/var/log/syslog更精准、更聚焦。
1.1 检查 rc.local 执行记录
如果你使用的是传统rc.local方式(如参考博文所示),首先要确认rc-local.service是否被 systemd 正确加载并运行:
systemctl status rc-local.service正常输出中应包含:
Active: active (exited) since ... ... Process: ... ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS)如果显示inactive (dead)或failed,说明rc.local根本没被调用。此时需检查:
/etc/rc.local文件是否存在且有执行权限(ls -l /etc/rc.local)- 文件首行是否为
#!/bin/sh -e(注意-e参数,出错会立即退出) exit 0是否在文件末尾(缺了会导致整个服务失败)
接着,查看该服务的详细日志:
sudo journalctl -u rc-local.service -n 50 --no-pager你会看到类似这样的关键行:
Mar 15 09:23:41 ubuntu rc.local[1234]: EnterBuildDir Mar 15 09:23:41 ubuntu rc.local[1234]: AfterSim判断依据:只要看到你的脚本中echo输出的字符串(如EnterBuildDir),就证明脚本已执行;若只看到Starting /etc/rc.local Compatibility...却无后续输出,则脚本可能因权限、路径或语法错误提前退出。
1.2 追踪脚本内部命令的执行痕迹
rc.local只是入口,真正干活的是你写的auto_run_test.sh。要确认它内部命令是否生效,不能只看rc-local.service日志,还要看脚本自身行为是否留下“物理证据”。
回到参考博文中的例子:
echo “helloStartup” > ./output.txt cd /home/user/mywbc_v5_usb/build echo “EnterBuildDir” > ./output.txt ./sim/sim echo “AfterSim” > ./outputend.txt这里的关键是:脚本里的echo和重定向操作,会在指定路径生成文件。所以最简单的验证方式就是——重启后立刻检查这些文件是否存在、内容是否正确:
# 检查 output.txt 是否生成,内容是否为 "EnterBuildDir" ls -l /home/user/Documents/scripts/output.txt cat /home/user/Documents/scripts/output.txt # 检查 outputend.txt 是否生成 ls -l /home/user/Documents/scripts/outputend.txt注意:./output.txt中的.表示当前工作目录。而rc.local中执行sudo sh auto_run_test.sh时,当前目录是/root(因为sudo切换到了 root 用户),不是你脚本所在的/home/user/Documents/scripts。所以参考博文中的写法实际会把文件写到/root/output.txt,而非预期位置。
修正建议:在脚本开头显式指定工作目录,避免路径歧义:
#!/bin/bash cd /home/user/Documents/scripts # 明确切换到脚本所在目录 echo "helloStartup" > ./output.txt cd /home/user/mywbc_v5_usb/build echo "EnterBuildDir" > ../scripts/output.txt # 写回原目录 ./sim/sim echo "AfterSim" > ../scripts/outputend.txt这样,无论在哪执行,输出文件都会落在你期望的位置,验证起来毫无悬念。
2. 检查进程与服务状态:确认关键程序是否“活”着
有些开机脚本的目标不是“执行完就结束”,而是“启动一个长期运行的后台程序”,比如./sim/sim。这时,光看日志和文件不够,必须确认这个程序是否真的在后台持续运行。
2.1 使用 ps 命令抓取实时进程快照
重启进入系统后,立即打开终端,运行:
ps aux | grep sim如果./sim/sim成功启动并常驻,你会看到类似输出:
user 12345 0.1 0.2 123456 7890 ? S 09:23 0:01 ./sim/sim其中12345是进程 PID,S表示休眠态(正常),0:01表示已运行 1 分钟。
❌ 如果只看到:
user 12345 0.0 0.0 2345 678 pts/0 R+ 09:25 0:00 grep --color=auto sim说明sim进程早已退出,grep自己成了唯一匹配项。
进阶技巧:用pgrep直接获取 PID,适合脚本化验证:
# 如果返回数字,说明进程存在;无输出则不存在 pgrep -f "sim/sim"2.2 为长期进程添加 systemd 服务(更可靠的管理方式)
rc.local启动的进程缺乏生命周期管理:崩溃不会自动重启,无法设置依赖关系,日志也不统一。对于./sim/sim这类关键程序,强烈建议改用systemd服务。
创建服务文件/etc/systemd/system/sim-runner.service:
[Unit] Description=SIM Runner Service After=network.target [Service] Type=simple User=user WorkingDirectory=/home/user/mywbc_v5_usb/build ExecStart=/home/user/mywbc_v5_usb/build/sim/sim Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target启用并启动:
sudo systemctl daemon-reload sudo systemctl enable sim-runner.service sudo systemctl start sim-runner.service验证方式变得极其简单:
# 查看服务整体状态 sudo systemctl status sim-runner.service # 查看最近 20 行运行日志 sudo journalctl -u sim-runner.service -n 20 --no-pager优势:systemctl status会清晰显示active (running)或failed,日志中会包含sim程序自身的 stdout/stderr 输出,比rc.local日志更完整、更易排查。
3. 添加自验证机制:让脚本自己“报平安”
最可靠的方法,是让脚本在执行完毕后,主动留下一个无可辩驳的“成功凭证”。这比事后翻日志、查进程更直接、更自动化。
3.1 时间戳标记法:一眼识别执行时刻
修改你的auto_run_test.sh,在脚本末尾添加一行:
echo "SUCCESS $(date '+%Y-%m-%d %H:%M:%S')" > /tmp/startup_check.log重启后,只需检查:
cat /tmp/startup_check.log # 输出示例:SUCCESS 2024-03-15 09:23:45为什么选/tmp:该目录每次启动都会清空,如果看到这个文件,100% 证明是本次启动时由脚本创建的。
3.2 网络回传验证法:跨设备确认(适合远程服务器)
如果你管理的是云服务器或树莓派,无法直接登录桌面,可以加一段轻量网络请求,让脚本执行成功后向你的个人服务器发个“心跳”:
# 在脚本末尾添加(需确保系统已安装 curl) curl -s "https://your-webhook.com/startup?host=$(hostname)&time=$(date -u +%s)" > /dev/null 2>&1你自己的服务器收到请求后,可以记录日志、发邮件或推送通知。即使你人在外地,也能第一时间知道脚本是否跑通。
注意:此方法需确保网络在脚本执行时已就绪(After=network-online.target),否则会超时失败。
4. 常见失败原因速查表:5 分钟定位问题根源
即使验证方法再全,也得知道往哪查。以下是rc.local开机脚本失败的 TOP 5 原因及对应检查命令:
| 问题现象 | 最可能原因 | 快速检查命令 | 解决方案 |
|---|---|---|---|
rc-local.service显示failed | /etc/rc.local权限不足或缺少exit 0 | ls -l /etc/rc.localsudo tail -n 5 /etc/rc.local | sudo chmod +x /etc/rc.local确保末尾有 exit 0 |
脚本中echo没生成文件 | 工作目录错误,./指向了/root | sudo ls -l /root/output.txt | 在脚本开头加cd /your/script/path |
./sim/sim进程找不到 | 脚本中cd失败,或sim依赖库缺失 | sudo journalctl -u rc-local.service | grep -A5 -B5 "sim" | 检查cd命令是否成功(加echo $?);用ldd ./sim/sim查依赖 |
| 日志里完全看不到脚本输出 | rc.local未被 systemd 启用 | sudo systemctl is-enabled rc-local.service | sudo systemctl enable rc-local.service |
Ubuntu 20.04+ 系统无rc.local | 新版 Ubuntu 默认禁用rc-local | ls /etc/systemd/system/rc-local.service* | 创建/etc/systemd/system/rc-local.service并启用 |
记住一个原则:所有失败,最终都会在journalctl -u rc-local.service的输出中留下线索。把它当作你的第一诊断工具,而不是最后才想起来。
5. 总结:建立你的开机脚本验证清单
验证不是一次性的动作,而是一套可复用的流程。建议你将以下四步加入日常部署 checklist,每次修改脚本后都走一遍:
- 日志确认:
sudo journalctl -u rc-local.service -n 50—— 看是否有你的echo输出; - 文件确认:
ls -l /expected/output/path—— 看关键文件是否生成、内容是否正确; - 进程确认:
pgrep -f "your_program"—— 看长期进程是否存活; - 自证确认:
cat /tmp/startup_check.log—— 看脚本是否主动留下成功标记。
这四步下来,脚本是否执行,再无任何疑问。你会发现,所谓“玄学”的开机问题,本质只是信息没被看见。而本文提供的,就是帮你把那些隐藏的信息,全部打捞上来。
下次再遇到“重启后脚本没反应”,别再怀疑人生,打开终端,按顺序敲四条命令——答案,就在那里。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。