init.d目录怎么用?结合测试脚本一看就明白
你是不是也遇到过这样的问题:写好了一个监控脚本、日志清理程序,或者自定义服务,想让它开机自动运行,却卡在了“到底该放哪”“怎么让它生效”这一步?别急,今天我们就用一个最简单的测试脚本,把/etc/init.d目录的用法彻底讲清楚——不堆概念,不绕弯子,跟着操作,三分钟就能跑通。
这篇文章专为刚接触 Linux 系统管理的朋友准备。无论你用的是 CentOS、Ubuntu 还是其他主流发行版,只要系统还在用 SysV init(不是纯 systemd 的精简环境),这套方法都管用。我们不讲抽象原理,只做一件事:让你亲手把一个脚本变成真正的开机启动服务。
1. 先写一个能“说话”的测试脚本
要想验证 init.d 是否生效,第一步得有个可观察的脚本。它不需要复杂功能,只要能在开机时留下痕迹就行——比如往日志里写一行字,或者创建一个临时文件。
我们来写一个极简的mytest.sh,放在/etc/init.d/下:
#!/bin/bash # /etc/init.d/mytest.sh # chkconfig: 2345 99 01 # description: A simple test service for init.d learning case "$1" in start) echo "[$(date)] mytest.sh started" >> /var/log/mytest.log touch /tmp/mytest_started ;; stop) echo "[$(date)] mytest.sh stopped" >> /var/log/mytest.log rm -f /tmp/mytest_started ;; restart) $0 stop $0 start ;; status) if [ -f /tmp/mytest_started ]; then echo "mytest.sh is running" else echo "mytest.sh is not running" fi ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0说明一下这个脚本的关键点:
- 第一行
#!/bin/bash告诉系统用 bash 解释执行;chkconfig行是给某些工具(如chkconfig命令)看的,声明它适用于运行级别 2/3/4/5,启动序号 99,停止序号 01;case结构支持start/stop/restart/status四种标准操作,这是 init.d 脚本的约定俗成;start时往/var/log/mytest.log写时间戳,并创建/tmp/mytest_started文件;stop时则清理它;- 所有操作都简单、可验证、无副作用。
保存后,给它加上可执行权限:
sudo chmod +x /etc/init.d/mytest.sh现在,你可以手动试一试:
sudo /etc/init.d/mytest.sh start sudo /etc/init.d/mytest.sh status如果看到mytest.sh is running,并且/tmp/mytest_started文件存在、/var/log/mytest.log里有新记录,说明脚本本身完全没问题——接下来,就是让它“自动”运行。
2. 理解运行级别:为什么是 rc5.d,而不是 rc3.d?
很多教程直接告诉你“去/etc/rc5.d/创建链接”,但没说清为什么。其实关键就藏在“系统当前运行在哪一级”里。
Linux 启动时,会进入一个预设的运行级别(runlevel),不同级别代表不同的系统状态:
0:关机1:单用户模式(维护用)2~5:多用户模式,其中3是命令行界面,5是带图形界面(GUI)6:重启
绝大多数桌面或服务器环境,默认进入的是级别 3 或 5。要确认你的系统用的是哪个,只需一条命令:
runlevel输出类似N 5或3 5,后面的数字就是当前运行级别(比如5)。这意味着:系统启动时,会自动执行/etc/rc5.d/目录下的所有以S开头的脚本。
小知识卡片:
/etc/init.d/是所有服务脚本的“源代码仓库”,统一存放,便于管理;/etc/rcX.d/(X 是 0~6)是“启动清单”,里面全是软链接,指向/etc/init.d/中的真实脚本;S开头 = Start(启动),K开头 = Kill(停止),后面的两位数字决定执行顺序(越小越早,越大越晚);- 比如
S20network会在S99mytest之前运行,确保网络先就绪,你的脚本再启动。
所以,runlevel不是可有可无的步骤,而是决定你该进哪个rcX.d目录的关键依据。
3. 创建软链接:让系统“认识”你的服务
确认了运行级别(假设是5),现在就去/etc/rc5.d/目录下,为你的脚本创建一个启动链接:
cd /etc/rc5.d/ sudo ln -s /etc/init.d/mytest.sh S99mytest注意命名规则:S+ 两位数字 + 服务名。这里用S99mytest,表示“在所有S脚本中最后启动”。如果你的服务依赖数据库或网络,把它放后面更稳妥;如果它本身是基础服务,可以改成S20mytest。
创建完成后,用ls查看:
ls -l S99*你应该看到类似这样的输出:
S99mytest -> /etc/init.d/mytest.sh这就意味着:系统启动到级别 5 时,会自动执行S99mytest,而它实际调用的就是/etc/init.d/mytest.sh start。
常见误区提醒:
- 不要直接把脚本复制到
rc5.d/,必须用ln -s创建软链接;- 链接名必须以
S或K开头,否则不会被识别为启动项;- 数字部分不能省略,也不能超出
01–99范围;- 如果你用的是 Ubuntu 16.04 及更老版本(仍默认使用 SysV init),这套流程完全适用;较新版本虽转向 systemd,但
/etc/init.d/仍被兼容支持。
4. 验证是否生效:不用重启也能测
很多人一上来就想reboot,其实大可不必。Linux 提供了更安全、更快捷的验证方式。
方法一:模拟启动流程(推荐)
直接运行S99mytest链接,效果等同于开机时的启动行为:
sudo /etc/rc5.d/S99mytest start然后检查:
ls -l /tmp/mytest_started tail -n 1 /var/log/mytest.log如果文件存在、日志有最新时间戳,恭喜,你的服务已成功“注册”。
方法二:用 service 命令统一管理
几乎所有发行版都支持service命令,它是调用 init.d 脚本的标准化接口:
sudo service mytest start sudo service mytest status你会发现,service mytest start实际上就是在后台调用/etc/init.d/mytest.sh start。这种写法更简洁,也更符合运维习惯。
方法三:检查启动项列表(可选)
有些系统提供chkconfig工具(CentOS/RHEL 常见),可以查看和管理 init.d 服务:
sudo chkconfig --list | grep mytest如果看到类似mytest 0:off 1:off 2:on 3:on 4:on 5:on 6:off的输出,说明它已在运行级别 2/3/4/5 启用。
提示:Ubuntu 默认不安装
chkconfig,可用sysv-rc-conf替代,或直接跳过,因为我们已经通过service和手动调用验证过了。
5. 真正的开机测试与排错指南
当你确信一切配置无误,就可以进行最终验证:重启系统。
sudo reboot等待机器重新启动并登录后,立即检查:
ls -l /tmp/mytest_started cat /var/log/mytest.log如果/tmp/mytest_started存在,且日志里有重启后的时间戳,说明你的脚本已真正实现开机自启。
如果失败了?别慌,按顺序排查:
检查脚本权限
确保/etc/init.d/mytest.sh有可执行权限:
ls -l /etc/init.d/mytest.sh # 应显示 -rwxr-xr-x检查链接是否正确
进入/etc/rc5.d/,确认软链接指向无误:
ls -l /etc/rc5.d/S99mytest # 必须指向 /etc/init.d/mytest.sh检查运行级别是否匹配
再次运行runlevel,确认当前级别与你创建链接的rcX.d目录一致。如果runlevel显示3,但你只在rc5.d创建了链接,那它自然不会启动。
检查脚本语法与路径
init.d 脚本对路径很敏感。确保脚本里所有命令(如echo、touch)都用绝对路径,或确保PATH环境变量足够宽泛。可以在脚本开头加一句:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin查看系统日志找线索
开机失败时,系统日志是最可靠的线索来源:
sudo journalctl -b | grep mytest # 或传统方式(SysV 环境) sudo tail -n 20 /var/log/messages | grep mytest错误信息往往直指问题核心,比如“Permission denied”、“No such file”等。
6. 进阶建议:让 init.d 脚本更专业
虽然我们的测试脚本已经能工作,但在真实生产环境中,还可以稍作增强,让它更健壮、更易维护:
6.1 添加 LSB 标头(提升兼容性)
在脚本开头#!/bin/bash下方,加入标准 LSB(Linux Standard Base)注释块:
### 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 service for init.d # Description: A simple script to demonstrate init.d usage ### END INIT INFO这些注释会被insserv(Debian/Ubuntu)或chkconfig(RHEL/CentOS)读取,用于自动分析依赖关系和生成正确的启动顺序,避免手动计算S/K数字。
6.2 使用标准日志工具
把echo ... >> /var/log/mytest.log替换为logger命令,让日志自动归入系统日志体系:
logger -t "mytest" "Service started"这样,日志会出现在/var/log/syslog(Ubuntu)或/var/log/messages(CentOS)中,方便统一收集和审计。
6.3 支持 reload 和 force-reload(可选)
很多服务支持热重载配置,可在case中增加:
reload|force-reload) echo "Reloading mytest configuration..." # 这里可以加重新读取配置文件的逻辑 ;;虽然测试脚本用不上,但这是专业服务脚本的标配。
7. 总结:init.d 的本质,就是一套“约定大于配置”的启动机制
回过头看,整个过程其实非常清晰:
/etc/init.d/是服务脚本的“中央仓库”,你把可执行脚本放在这里;/etc/rcX.d/是“启动菜单”,用Sxxname和Kxxname软链接告诉系统“在哪个级别、按什么顺序启动或停止”;runlevel命令帮你找准菜单编号;service命令是面向用户的友好接口,背后仍是调用 init.d;- 所有操作都基于文件系统和 shell,没有黑盒,全靠约定(比如脚本必须支持
start/stop参数)。
它不炫酷,也不时髦,但它稳定、透明、可调试。哪怕今天你用的是 systemd,理解 init.d 依然是打通 Linux 启动逻辑的关键一环。
现在,你已经亲手完成了一次完整的开机启动服务配置。下一步,可以把任何你写的 Python 监控脚本、Shell 日志轮转程序、甚至 Node.js 服务,都按这个模式包装起来,让它真正融入系统生命周期。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。