news 2026/4/18 12:51:16

为什么要用S开头命名?测试开机启动脚本告诉你答案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么要用S开头命名?测试开机启动脚本告诉你答案

为什么要用S开头命名?测试开机启动脚本告诉你答案

你有没有遇到过这样的情况:写好了一个服务脚本,放进/etc/init.d/目录,也加了执行权限,还手动运行测试没问题,可一重启系统,脚本却压根没跑起来?
或者更奇怪的是——它倒是运行了,但比数据库、网络服务还早启动,结果因为依赖没就绪,直接报错退出?

这个问题背后,藏着 Linux 系统启动机制里一个看似简单、实则关键的约定:为什么开机自启脚本的软链接必须以S开头?

今天我们就用「测试开机启动脚本」这个轻量级镜像,从零开始走一遍真实流程,不讲抽象概念,只看命令、目录、文件名和实际效果。你会发现,那个小小的S,不是随意写的字母,而是系统启动顺序的“交通指挥员”。


1. 先搞清楚:系统启动时到底在做什么?

Linux 启动不是一股脑儿把所有脚本全拉起来,而是分阶段、按顺序、有依赖地加载服务。这个机制叫SysV init(虽然现代发行版多用 systemd,但/etc/init.d/+rc*.d这套逻辑仍在兼容层广泛存在,尤其在 CentOS 7 之前、Ubuntu 16.04 及更老版本中仍是默认行为)。

核心逻辑就两点:

  • 每个运行级别(runlevel)对应一个启动目录,比如rc3.d(多用户无图形)、rc5.d(带图形界面);
  • 这些目录里不放脚本本身,只放指向/etc/init.d/中脚本的软链接
  • 而这些软链接的名字,决定了它们是“启动”还是“停止”,以及“什么时候启动”。

所以,S不是“Start”的缩写那么简单——它是整个启动序列的开关标识符。


2. 动手验证:看看你的系统在哪个运行级别

我们先确认当前系统的运行级别,这是后续操作的前提。

runlevel

输出类似:

N 5

说明:上次启动后进入的是运行级别 5(即带桌面环境的完整多用户模式)。
那系统启动时,就会自动去读取/etc/rc5.d/目录下的所有软链接,并按名字顺序执行。

小知识:N表示“None”,代表系统刚启动,还没切换过运行级别;第二个数字5才是当前级别。

你也可以用who -r命令再次验证:

who -r

输出中会明确显示run-level 5


3. 揭秘/etc/rc5.d/:一个全是SK的目录

现在,我们进到这个关键目录看看里面到底有什么:

ls -l /etc/rc5.d/

你会看到一堆类似这样的文件名:

S01rsyslog S10network S20ssh S25mysql S99myapp K01apache2 K10docker

注意观察命名规律:

  • 所有以S开头的,都是启动脚本(Start);
  • 所有以K开头的,都是关闭脚本(Kill),用于系统关机或切换运行级别时停止服务;
  • 后面的两位数字(如012099)表示执行顺序:数字越小越早执行,越大越晚。

举个真实例子:S10networkS25mysql之前运行,确保网络就绪后,MySQL 才能连接外部配置或远程存储;而S99myapp排在最后,说明它依赖前面几乎所有基础服务。

这正是S的真正价值:它不只是“要启动”,更是“在什么时机启动”。


4. 实操:创建你的第一个S开头软链接

假设你已经写好一个测试脚本/etc/init.d/mytest.sh,内容如下(仅作演示,无需复杂逻辑):

#!/bin/bash # /etc/init.d/mytest.sh case "$1" in start) echo "mytest.sh started at $(date)" >> /var/log/mytest.log ;; stop) echo "mytest.sh stopped at $(date)" >> /var/log/mytest.log ;; *) echo "Usage: $0 {start|stop}" exit 1 ;; esac exit 0

给它加上执行权限:

chmod +x /etc/init.d/mytest.sh

现在,我们为它创建一个软链接,放在/etc/rc5.d/下,并命名为S99mytest

ln -s /etc/init.d/mytest.sh /etc/rc5.d/S99mytest

注意:这里必须是S99mytest,不能写成myteststart-mytest99mytest—— 缺少S,系统启动时根本不会识别它为启动项。

再检查一下是否成功:

ls -l /etc/rc5.d/S99mytest

输出应类似:

lrwxrwxrwx 1 root root 22 Apr 5 10:20 /etc/rc5.d/S99mytest -> /etc/init.d/mytest.sh

成功!这个链接已就位,只等下次启动。


5. 为什么不能用S00S99随便选?顺序真的重要吗?

答案是:极其重要。我们来用一个对比实验说明。

场景模拟:两个脚本,不同启动序号

  • S10db.sh:模拟数据库服务,启动耗时约 3 秒,启动后监听3306端口;
  • S20app.sh:模拟应用服务,启动时尝试连接localhost:3306

如果把应用脚本命名为S05app.sh(比数据库还早),会发生什么?

[启动日志片段] Apr 05 10:30:01 S05app.sh: connecting to localhost:3306... Apr 05 10:30:01 S05app.sh: connection refused → exit with error Apr 05 10:30:04 S10db.sh: MySQL started, listening on 3306

应用失败了,不是代码问题,而是时机错了

而如果你把它改成S20app.sh,日志就会是:

Apr 05 10:30:01 S10db.sh: MySQL started, listening on 3306 Apr 05 10:30:04 S20app.sh: connected to database → app ready

所以,S后面的数字不是编号游戏,而是服务依赖关系的显式表达
这也是为什么文档里特别提醒:“如果进程需要访问数据库或者有其他依赖项,最好把启动序号调大”。


6. 验证效果:重启不是唯一方式,还有更安全的测试法

当然,你可以直接reboot,但频繁重启既慢又影响工作。其实有更高效的方式验证:

方法一:手动触发启动(推荐)

sudo /etc/init.d/mytest.sh start

然后检查日志:

tail -n 1 /var/log/mytest.log # 输出应为:mytest.sh started at ...

方法二:模拟 rc5.d 启动流程

# 进入 rc5.d 目录,只执行所有 S 开头的脚本(跳过 K) cd /etc/rc5.d/ for i in S*; do [ -x "$i" ] && sudo ./"$i" start; done

这个命令会按字母顺序(也就是数字顺序)依次执行所有Sxx*脚本的start参数,效果和开机时完全一致。

提示:执行前确保脚本里case "$1"分支正确处理了start,且没有硬编码路径错误。


7. 常见误区与排错指南

很多同学卡在这一步,不是不会操作,而是被几个“看起来合理、实则致命”的错误绊住。我们一一拆解:

❌ 误区 1:脚本放在/etc/init.d/就自动启动了

→ 错。/etc/init.d/只是“脚本仓库”,系统启动时只扫描rc*.d/下的软链接,不读取init.d/里的文件。

❌ 误区 2:软链接名写成S99-mytestS99_mytest

→ 错。SysV init 严格匹配SXXname格式(XX是纯数字,name是任意字符,中间不能有短横线、下划线或空格)。否则会被忽略。

❌ 误区 3:忘记给脚本加#!/bin/bash或执行权限

→ 错。即使软链接存在,若原脚本不可执行,启动时会报Permission denied或静默失败。

❌ 误区 4:在 Ubuntu 20.04+ 或 CentOS 8+ 上强行套用这套逻辑

→ 需谨慎。这些系统默认使用systemdrc*.d仅为兼容保留。若需长期使用,建议改写为.service文件。但本镜像定位明确:专为 SysV init 环境设计,适用于 CentOS 6/7、Ubuntu 14.04/16.04 等经典场景

快速排错三步法:

  1. ls -l /etc/rc5.d/S*mytest*→ 确认软链接存在且指向正确;
  2. sudo /etc/init.d/mytest.sh start→ 确认脚本本身可手动运行;
  3. sudo systemctl is-active mytest(如支持)或查/var/log/syslog→ 看启动时是否有报错。

8. 总结:那个S,到底在说什么?

回看标题——“为什么要用 S 开头命名?”
现在答案很清晰了:

  • SStart 的强制标识符,没有它,系统根本不认为这是一个启动项;
  • S后的数字是启动优先级的声明,不是编号,而是对依赖关系的承诺;
  • 整个rc5.d/目录是一张启动时序图,每个Sxx链接都是图上的一个节点;
  • 你写的每一个S99xxx,都在向系统说:“请在我依赖的所有服务之后,再启动我。”

这不是古董机制,而是稳定、透明、可审计的启动哲学。哪怕今天你用的是 Docker 或 Kubernetes,理解这套逻辑,依然能帮你快速诊断容器内 init 进程行为、调试嵌入式设备启动脚本,甚至读懂老系统的运维手册。

所以,下次再看到S20nginxS99custom-monitor,别只把它当个文件名——那是 Linux 启动交响乐中,属于它的节拍器。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:40:00

嵌入式系统瘦身术:Yocto组件去除深度剖析

以下是对您提供的博文《嵌入式系统瘦身术:Yocto组件去除深度剖析》的全面润色与重构版本。本次优化严格遵循您的全部要求:✅ 彻底消除AI生成痕迹,语言自然、专业、有“人味”——像一位深耕Yocto十年的嵌入式架构师在技术博客中娓娓道来&…

作者头像 李华
网站建设 2026/4/18 11:00:31

测试开机启动脚本镜像帮助文档解读,实用技巧

测试开机启动脚本镜像帮助文档解读,实用技巧 你有没有遇到过这样的情况:写好了一个监控脚本、日志清理工具或者自定义服务,每次重启服务器后都要手动运行一次?反复操作不仅费时,还容易遗漏。更糟的是,在无…

作者头像 李华
网站建设 2026/4/17 18:06:17

用YOLOv12镜像做零售货架分析实战案例

用YOLOv12镜像做零售货架分析实战案例 在便利店、超市和无人货柜的日常运营中,货架商品识别与状态监控一直是个“看得见却管不着”的难题。人工巡检效率低、漏检率高;传统CV方案泛化差、换品牌就要重训练;而部署一个能跑在边缘设备上的实时检…

作者头像 李华
网站建设 2026/4/18 8:40:27

用Qwen3-Embedding-0.6B搭建轻量级RAG系统,实战应用指南

用Qwen3-Embedding-0.6B搭建轻量级RAG系统,实战应用指南 在构建企业级知识问答、智能客服或文档助手时,RAG(检索增强生成)已成为最主流的技术路径。但很多团队卡在第一步:如何选一个既轻量又靠谱的嵌入模型&#xff1…

作者头像 李华
网站建设 2026/4/18 8:16:44

Conda安装Unsloth失败?这个方法100%成功

Conda安装Unsloth失败?这个方法100%成功 你是不是也遇到过这样的情况:在终端里敲下 conda install unsloth,结果提示“package not found”;或者按官方文档执行 conda create --name unsloth_env pytorch-cuda12.1 ...&#xff0…

作者头像 李华
网站建设 2026/4/18 7:52:06

免费算力+Qwen3-1.7B,零成本入门大模型微调实战

免费算力Qwen3-1.7B,零成本入门大模型微调实战 在大模型技术快速演进的今天,很多人想动手实践微调,却被三座大山拦住去路:显卡太贵、环境太杂、教程太绕。但其实,一条轻量、真实、可复现的入门路径已经摆在眼前——用…

作者头像 李华