当前位置: 首页 > news >正文

为什么要用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星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.jsqmd.com/news/301460/

相关文章:

  • 尹邦奇:GEO不是SEO升级版,而是内容工程革命
  • 零基础也能玩转YOLOv13?官方镜像让目标检测变简单
  • 升级Qwen3-1.7B后,AI交互体验大幅提升
  • 人像占比小也能抠?BSHM实际测试结果告诉你真相
  • 新手教程:理解Arduino Uno使用的ATmega328P数据手册
  • 用Qwen3-Embedding-0.6B搭建轻量级RAG系统,实战应用指南
  • 5分钟上手fft npainting lama:零基础实现图片重绘修复
  • ALU小白指南:从零认识数字电路模块
  • 暗光照片效果差?建议补光后再处理
  • Qwen-Image-2512-ComfyUI为什么这么火?真实用户反馈揭秘
  • 零基础搞定人像抠图!BSHM镜像一键启动实测
  • ESP32 Arduino环境搭建:手把手教程(从零开始)
  • gpt-oss-20b-WEBUI支持多平台,跨设备体验一致
  • verl初学者避坑清单:这8个问题要注意
  • OpenAI 别太卷了!300+ 官方提示词包全免费?
  • 一文搞懂YOLOv13镜像的安装与推理操作
  • 波形发生器反馈网络设计:精度提升实战方法
  • 亲测有效!调整相似度阈值让CAM++识别更精准
  • GPEN在老照片修复中的实际应用,落地方案详解
  • PMBus告警响应命令流程:系统性全面讲解
  • Glyph视觉推理保姆级教程,新手也能轻松上手
  • YOLOE开放词汇检测,再也不怕新类别了
  • Glyph模型推理界面怎么用?详细图文说明
  • 小批量PCB试产指南:新手必看的厂家选择要点
  • AI开发者福音:Unsloth开源框架让微调变得又快又省
  • 删除Z-Image-Turbo历史图片很简单,几个命令全搞定
  • PCB生产流程与硬件设计协同:全面讲解
  • 多设备协同工作?局域网访问设置全攻略
  • 零基础也能懂的语音端点检测:FSMN-VAD保姆级教程
  • 一键启动YOLOv10!官方镜像让部署不再踩坑