rc5.d目录作用揭秘,搭配测试脚本更好懂
你有没有遇到过这样的问题:写好了开机自启脚本,却怎么也等不到它自动运行?改了配置、加了权限、甚至重启了三遍,结果系统启动后一查进程,脚本压根没跑——不是脚本写错了,而是你还没真正搞懂/etc/rc5.d/这个看似普通、实则关键的目录。
它不像/etc/init.d/那样直接放着可执行脚本,也不像systemd那样有清晰的服务单元文件。它更像一个“调度中心”:不干活,但决定谁先干、谁后干、谁该干、谁不该干。今天我们就抛开抽象概念,用一个真实可运行的测试脚本,一层层拆解rc5.d的真实作用——不讲术语堆砌,只讲你重启后能看到的变化。
1. 先跑起来:一个能验证的测试脚本
别急着进目录、建链接。我们先准备一个“会说话”的脚本——它不干复杂事,只在开机时往日志里写一行字,再启动一个轻量进程。这样你一眼就能确认:它到底有没有被系统执行。
1.1 创建测试脚本/etc/init.d/mytest.sh
sudo tee /etc/init.d/mytest.sh << 'EOF' #!/bin/bash ### BEGIN INIT INFO # Provides: mytest # Required-Start: $local_fs $network # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Test startup script for rc5.d # Description: Logs boot time and starts a dummy process ### END INIT INFO case "$1" in start) echo "$(date): mytest.sh STARTED via rc5.d" >> /var/log/mytest.log # 启动一个后台sleep进程,方便我们用ps验证是否真在运行 nohup sleep 3600 > /dev/null 2>&1 & echo $! > /var/run/mytest.pid echo "mytest started (PID: $(cat /var/run/mytest.pid))" ;; stop) if [ -f /var/run/mytest.pid ]; then kill "$(cat /var/run/mytest.pid)" 2>/dev/null rm -f /var/run/mytest.pid echo "$(date): mytest.sh STOPPED" >> /var/log/mytest.log fi ;; restart) $0 stop sleep 1 $0 start ;; status) if [ -f /var/run/mytest.pid ] && kill -0 "$(cat /var/run/mytest.pid)" 2>/dev/null; then echo "mytest is running (PID: $(cat /var/run/mytest.pid))" else echo "mytest is not running" fi ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 EOF1.2 设置权限并手动测试
sudo chmod +x /etc/init.d/mytest.sh sudo /etc/init.d/mytest.sh start检查效果:
# 查看日志是否写入 sudo tail -n 1 /var/log/mytest.log # 查看进程是否启动 ps aux | grep "sleep 3600" | grep -v grep如果看到时间戳日志和sleep进程,说明脚本本身完全正常——问题一定出在“怎么让它开机自动跑”这个环节。
2. 真正的起点:系统运行级别不是玄学
很多人跳过这步,直接进rc5.d目录,结果发现脚本没执行,就开始怀疑人生。其实,rc5.d是否生效,取决于系统当前“运行在哪一级”。
2.1 什么是运行级别(Runlevel)?
你可以把它理解成系统的“工作模式”:
runlevel 0:关机runlevel 1:单用户维护模式(类似安全模式)runlevel 2-5:多用户模式,其中5是带图形界面的完整多用户环境(绝大多数桌面版 Ubuntu/CentOS 默认就是 5)runlevel 6:重启
注意:现代 systemd 系统(如新版 Ubuntu 20.04+、CentOS 7+)已不再严格依赖传统 runlevel,但
/etc/rc5.d/仍被兼容保留,并由sysvinit兼容层或rc-local服务触发。本文所有操作在Ubuntu 18.04/20.04 和 CentOS 7上均实测有效。
2.2 查看当前运行级别
runlevel输出示例:
N 5- 第一个字符
N表示“未切换过”,即开机后一直保持初始级别 - 第二个字符
5就是当前运行级别 → 这意味着:系统启动时,会自动执行/etc/rc5.d/下所有以S开头的脚本
如果你看到的是N 3(无图形界面),那你要操作的就是/etc/rc3.d/,而不是rc5.d。别凭经验硬套,务必先runlevel。
3. 揭秘/etc/rc5.d/:它到底存了什么?
现在我们终于可以打开这个神秘目录了:
ls -l /etc/rc5.d/你会看到一堆形如S20nginx、S50rsyslog、K90network的文件。它们全都是软链接(symbolic links),不是真实脚本。
3.1 名字规则 = 执行逻辑
| 文件名示例 | 含义 |
|---|---|
S99mytest | S= Start(启动),99= 启动顺序(数字越大越靠后),mytest= 标识名 |
K10mysql | K= Kill(停止),10= 停止顺序(数字越小越先停),mysql= 标识名 |
关键点:
S和K决定“做什么”,数字决定“什么时候做”,名字只是便于识别——它不决定功能,只决定排序。
3.2 它们指向哪里?
随便看一个链接:
ls -l /etc/rc5.d/S50rsyslog输出类似:
S50rsyslog -> ../init.d/rsyslog→ 所有rc5.d/下的链接,最终都指向/etc/init.d/下的真实脚本。
所以/etc/rc5.d/的本质是:一个按启动顺序组织的、指向/etc/init.d/脚本的“快捷方式集合”。它不存代码,只存调度策略。
4. 动手创建链接:让脚本真正接入启动流程
既然rc5.d只认链接,那我们就亲手加一个。
4.1 创建软链接(重点:命名与位置)
sudo ln -s /etc/init.d/mytest.sh /etc/rc5.d/S99mytestS99mytest:S表示启动,99表示最后启动(确保数据库、网络等基础服务已就绪),mytest是你的标识- 为什么是
99?因为常见服务如S20ssh、S50apache2都在中间,99是安全兜底位,避免依赖冲突
4.2 验证链接是否正确
ls -l /etc/rc5.d/S99mytest应输出:
S99mytest -> /etc/init.d/mytest.sh链接存在、指向正确、权限继承自源脚本(无需额外chmod)。
5. 测试:重启不是终点,验证才是关键
别急着reboot。先模拟一次启动过程,快速验证逻辑是否通:
sudo /etc/init.d/rc5.d/S99mytest start然后检查:
sudo tail -n 1 /var/log/mytest.log # 应看到新时间戳 ps aux | grep "sleep 3600" | grep -v grep # 应看到进程模拟成功,再正式重启:
sudo reboot5.1 重启后第一件事:检查日志
等系统起来后,立刻执行:
sudo cat /var/log/mytest.log如果看到类似:
Wed Jun 12 10:24:33 CST 2024: mytest.sh STARTED via rc5.d恭喜,你的脚本已被rc5.d成功调度!
5.2 进阶验证:确认执行时机
想确认它是不是真在“图形界面启动前”就跑了?查系统启动日志:
sudo journalctl -b | grep "mytest" # 或传统系统用 sudo cat /var/log/boot.log | grep mytest你会发现它的日志时间,早于lightdm(Ubuntu)或gdm(CentOS)的启动记录——这正是rc5.d的价值:在 GUI 准备就绪前,就为你准备好后台服务。
6. 常见陷阱与避坑指南(血泪总结)
很多失败不是因为不会操作,而是踩中了这些隐蔽坑:
6.1 坑一:脚本缺少 LSB 头部注释
如果你的脚本没有### BEGIN INIT INFO这段标准头部,某些系统(尤其是较新 Ubuntu)可能忽略它,即使链接存在也不执行。
解决:务必复制本文开头的完整脚本,包含全部 LSB 注释块。
6.2 坑二:权限问题 ≠ 执行权限
/etc/init.d/mytest.sh必须有+x权限,但/etc/rc5.d/S99mytest作为软链接,不需要单独设权限。设了反而可能出错。
验证命令:
ls -l /etc/init.d/mytest.sh # 应含 x ls -l /etc/rc5.d/S99mytest # 软链接权限显示 lrwxrwxrwx,正常6.3 坑三:运行级别误判
runlevel显示N 5,不代表下次重启还是5。某些云服务器或最小化安装可能默认3;某些桌面环境可能因显卡驱动问题降级到3。
终极保险方案:同时为多个级别创建链接:
sudo ln -s /etc/init.d/mytest.sh /etc/rc2.d/S99mytest sudo ln -s /etc/init.d/mytest.sh /etc/rc3.d/S99mytest sudo ln -s /etc/init.d/mytest.sh /etc/rc4.d/S99mytest sudo ln -s /etc/init.d/mytest.sh /etc/rc5.d/S99mytest6.4 坑四:rc5.d在 systemd 系统中并非唯一路径
在纯 systemd 环境(如 Ubuntu 22.04+),推荐改用systemd服务单元。但/etc/rc5.d/仍被rc-local.service兼容支持。若发现不生效,可临时启用传统 rc.local:
sudo systemctl enable rc-local sudo systemctl start rc-local7. 总结:rc5.d 不是黑盒,而是可读的启动地图
我们从一个能打印日志的脚本出发,亲手验证了rc5.d的完整作用链:
- 它不存储逻辑,只定义执行顺序与动作类型(S/K)
- 它不运行脚本,只通过软链接调用
/etc/init.d/中的真实程序 - 它的生效前提,是
runlevel确实为5(或你配置的对应级别) - 它的价值,在于让启动过程变得可预测、可调试、可干预——你永远知道
S99mytest会在S50apache2之后、GUI 之前执行
与其把它当成一个需要死记硬背的目录,不如把它看作一张“开机任务清单”。你写的每个Sxx链接,都是在这张清单上亲手写下的一行待办事项。
下一次,当你再看到S20network、S99cloud-init,你就知道:这不是随机命名,而是一份精确到秒级的系统启动契约。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。