Linux开机自启原来这么简单,测试脚本真实体验
你有没有遇到过这样的场景:服务器重启后,需要手动启动监控服务、挂载NAS、开启日志采集,或者运行某个关键脚本?每次都要SSH登录、cd到目录、执行命令、加nohup……繁琐又容易遗漏。其实,Linux早就为你准备了一条“捷径”——不用装额外工具、不依赖systemd复杂配置、不改服务单元文件,只要三分钟,就能让任意脚本在系统就绪后自动跑起来。
本文不是讲理论,而是带你亲手完成一次真实、可验证的开机自启测试。我们用最轻量的方式,在Ubuntu环境下部署一个“开机打印时间戳+写入日志”的测试脚本,全程可复制、可复现、无坑可踩。所有操作基于系统原生机制,兼容Ubuntu 16.04、20.04、22.04及主流嵌入式Linux(如Tina)——它不挑版本,只讲实效。
1. 为什么选/etc/rc.local?它真的还管用吗?
很多人听说/etc/rc.local是“老古董”,担心在新版systemd系统里已被废弃。但事实是:它依然有效,且被官方保留为兼容入口。Ubuntu 20.04+默认虽未启用rc.local服务,但只需启用一次,它就稳稳工作;而Ubuntu 16.04和Tina等传统init系统则原生支持。
它的核心优势在于:
- 零学习成本:不需要理解unit文件语法、target依赖、ExecStartPre等概念
- 所见即所得:你写的每行命令,就是开机时真实执行的顺序
- 调试极简:出错直接看
/var/log/syslog或手动执行sudo /etc/rc.local即可复现 - 跨平台友好:从树莓派到工控机,从OpenWrt到Tina,只要带init,基本都认它
小知识补丁:
rc.local本质是一个Shell脚本,由init进程在多用户模式(runlevel 3/5)最后阶段调用。它不参与服务依赖图谱,因此适合执行“收尾型”任务——比如网络已通、磁盘已挂、环境已就绪后的轻量操作。
2. 动手实测:三步完成开机自启脚本部署
我们不搞虚的。下面这个测试脚本会做两件事:
① 在开机时记录精确时间戳;
② 将时间写入/var/log/boot-test.log,方便你重启后立刻验证是否生效。
整个过程无需安装任何包,纯系统自带能力。
2.1 创建测试脚本并赋予可执行权限
打开终端,执行以下命令:
# 创建日志目录(确保路径存在) sudo mkdir -p /var/log # 创建测试脚本内容(使用echo追加,避免覆盖原有rc.local) sudo tee /etc/rc.local << 'EOF' #!/bin/bash # 开机自启测试脚本 —— 记录启动时间戳 echo "=== System booted at $(date '+%Y-%m-%d %H:%M:%S') ===" >> /var/log/boot-test.log echo "Hostname: $(hostname)" >> /var/log/boot-test.log echo "Uptime: $(uptime)" >> /var/log/boot-test.log echo "" >> /var/log/boot-test.log exit 0 EOF # 赋予执行权限(关键!否则init会跳过) sudo chmod +x /etc/rc.local注意事项:
<< 'EOF'中的单引号防止当前shell提前变量替换,确保$(date)等命令在开机时才执行exit 0必须保留,且必须是最后一行——这是rc.local的退出约定,缺了会导致后续服务卡住- 不要用
sudo vim /etc/rc.local手动编辑,易引入不可见字符或换行错误;tee方式更安全可靠
2.2 (仅Ubuntu 20.04+必需)启用rc-local服务
如果你用的是Ubuntu 20.04或更新版本,需额外启用systemd对rc.local的支持:
# 创建systemd服务单元(如果不存在) sudo systemctl enable rc-local.service # 检查服务状态(应显示loaded enabled) sudo systemctl status rc-local.service | grep -E "(Loaded|Active)" # 查看服务日志(确认无报错) sudo journalctl -u rc-local.service --since "1 hour ago" | tail -n 10验证成功标志:
Loaded: loaded (/lib/systemd/system/rc-local.service; enabled; vendor preset: enabled)
❌ 常见失败原因:/etc/rc.local无执行权限、缺少exit 0、脚本内有语法错误(如未转义的$)
2.3 立即测试:不重启也能验证逻辑
别等重启!用这条命令模拟开机调用流程,快速验证脚本是否能正常运行:
# 手动执行rc.local(以root身份) sudo /etc/rc.local # 查看日志输出是否新增 sudo tail -n 5 /var/log/boot-test.log你应该看到类似这样的输出:
=== System booted at 2024-06-15 14:22:38 === Hostname: ubuntu-server Uptime: 14:22:38 up 2 days, 3:17, 1 user, load average: 0.01, 0.02, 0.05成功!说明脚本语法正确、路径可写、命令可用。接下来只需一次重启,它就会真正“上岗”。
3. 重启验证与常见问题排查
现在,执行一次真实重启:
sudo reboot等待系统重新上线后,立即检查结果:
# 查看日志是否新增一行(注意时间是否为本次重启后) sudo cat /var/log/boot-test.log # 或者只看最新一条记录(更清晰) sudo tail -n 3 /var/log/boot-test.log3.1 如果没看到新日志?按顺序排查这四点
| 排查项 | 检查命令 | 正常表现 | 异常处理 |
|---|---|---|---|
| rc.local是否可执行 | ls -l /etc/rc.local | 权限含x(如-rwxr-xr-x) | sudo chmod +x /etc/rc.local |
| exit 0是否存在且在末尾 | sudo tail -n 1 /etc/rc.local | 显示exit 0 | 用sudo nano /etc/rc.local补上,保存退出 |
| rc-local服务是否启用(Ubuntu 20.04+) | sudo systemctl is-enabled rc-local | 输出enabled | sudo systemctl enable rc-local.service |
| 系统日志是否有报错 | sudo journalctl -b | grep -i "rc.local|rc-local" | 无ERROR或FAILED字样 | 根据报错提示修正命令(如路径不存在、命令未安装) |
实用技巧:若脚本中调用了
python3、curl等非基础命令,建议写全路径(如/usr/bin/python3),避免PATH环境变量未加载导致失败。
3.2 进阶技巧:让脚本更健壮、更可控
真实业务中,你可能需要更多控制力。以下是几个经实战验证的小技巧:
延迟执行:某些服务(如Docker、MySQL)启动稍慢,可在脚本中加等待
# 等待网络就绪(最多30秒) for i in $(seq 1 30); do ping -c1 8.8.8.8 &>/dev/null && break; sleep 1; done防重复写入:用
date加毫秒避免日志时间戳冲突echo "Boot at $(date '+%Y-%m-%d %H:%M:%S.%3N')" >> /var/log/boot-test.log静默失败不中断:在关键命令后加
|| true,避免单条失败导致后续不执行/home/user/start-monitor.sh || true记录执行状态:加一句
echo "[OK] rc.local executed"便于日志追踪
这些都不是必须的,但当你从“能用”迈向“好用”时,它们就是省心的关键。
4. 它能做什么?不止是打印时间戳
别小看这个简单的机制。/etc/rc.local就像一个“系统启动后的万能钩子”,只要你能用Shell表达,它就能帮你自动执行。以下是几个真实场景中的典型用法:
4.1 网络相关自动化(最常用)
# 启用无线网卡并连接指定AP(Ubuntu桌面版) sudo ip link set wlan0 up sudo wpa_cli -i wlan0 reconfigure # 挂载远程NAS(需提前配置/etc/fstab或此处直接mount) sudo mount -t cifs //192.168.1.100/share /mnt/nas -o username=user,password=pass # 设置静态路由(工业网关场景) sudo ip route add 10.20.30.0/24 via 192.168.1.14.2 硬件与外设初始化
# 加载GPIO驱动(树莓派/嵌入式设备) echo 18 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio18/direction echo 1 > /sys/class/gpio/gpio18/value # 设置USB摄像头参数(避免自动休眠) echo 'options uvcvideo video_nr=0' | sudo tee /etc/modprobe.d/uvcvideo.conf sudo modprobe -r uvcvideo && sudo modprobe uvcvideo4.3 应用服务轻量启动
# 启动Python后台服务(无守护进程管理时) cd /opt/myapp && nohup python3 server.py > /var/log/myapp.log 2>&1 & # 启动Node.js应用(生产环境建议用pm2,但测试足够) cd /var/www/html && nohup node app.js > /var/log/node-app.log 2>&1 &注意:对于长期运行的服务,推荐使用systemd或supervisor进行进程管理;
rc.local更适合“一次性初始化”或“轻量级触发”。但它胜在简单、透明、易维护。
5. 总结:简单,才是最高级的工程智慧
我们走完了完整闭环:从理解原理、编写脚本、授权执行、启用服务、手动验证,到最终重启确认。整个过程没有一行多余代码,没有一个陌生概念,甚至不需要记住新命令——你只是把想做的事,用最直白的Shell语言写下来,然后告诉系统:“开机时,请照着做。”
这不是过时的方案,而是被时间验证过的务实选择。当复杂性成为负担,简单就是生产力。/etc/rc.local不会让你成为Shell大师,但它能让你在五分钟内解决一个真实问题。
下次再遇到“开机要自动干点啥”的需求,别急着搜systemd教程,先试试这个老朋友。你会发现,Linux的优雅,往往藏在最朴素的路径里。
6. 下一步建议
- 把本文的测试脚本改成你自己的业务命令(比如启动你的AI服务、挂载模型盘、初始化传感器)
- 在Tina或OpenWrt设备上复现一次,感受嵌入式Linux的简洁力量
- 对比
rc.local与systemd timer的适用边界:前者适合“开机即刻执行”,后者适合“开机后定时轮询” - ❌ 不要删除
exit 0,不要跳过权限设置,不要在脚本里写交互式命令(如read)
你已经掌握了Linux开机自启最本质的能力。剩下的,只是把它用在该用的地方。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。