0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【技术分享】正确编写SysV Init脚本以实现Systemd兼容(上)

ZLG致远电子 2025-10-28 11:45 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群


嵌入式的ubuntu系统如何写好SysV Init脚本呢?与system服务又有什么差别呢?一起随着文章来探究吧。


79a40b4e-b3b0-11f0-8ce9-92fbcf53809c.jpg  问题背景

许多传统Linux服务仍使用SysV Init脚本(/etc/init.d/),但在Systemd系统中,这些脚本需通过systemd-sysv-generator换为原生服务单元。若脚本未遵循Linux Standard Base (LSB)规范,会导致以下问题:

  1. 服务启动/停止有误:缺失关键命令(如status)或错误退出码。
  2. 依赖混乱:未声明依赖关系,导致服务启动顺序错误。
  3. 日志污染:输出未重定向,干扰Systemd日志(journald)。


79a40b4e-b3b0-11f0-8ce9-92fbcf53809c.jpg  SysV Init脚本规范指南

1. 必须支持的标准命令脚本需实现以下命令:

1.case"$1"in2.start)3.# 启动服务逻辑4.;;5.stop)6.# 停止服务逻辑7.;;8.restart)9.# 建议直接调用自身stop再start,或委托给Systemd10.$0stop11.$0start12.;;13.status)14.# 返回服务运行状态(必需!)15.ifpidof -x"$DAEMON">/dev/null;then16.echo"Service is running"17.exit018.else19.echo"Service is stopped"20.exit3# LSB规范:未运行状态码21.fi22.;;23.*)24.echo"Usage:$0{start|stop|restart|status}"25.exit1esac

2. LSB头部注释(必需)在脚本开头添加元数据:

1.### BEGIN INIT INFO2.# Provides: my_service3.# Required-Start: $network $syslog4.# Required-Stop: $network $syslog5.# Default-Start: 23456.# Default-Stop: 0167.# Short-Description: My Custom Service8.# Description: This service does something magical.

  • Provides:服务名称,需唯一。
  • Required-Start/Stop:定义依赖的其他服务或设施如($network表示网络就绪)。

3. 正确退出状态码退出码含义

  • 0 成功
  • 1 泛型错误
  • 2 无效命令参数
  • 3 服务未运行(status命令专用)
  • 4 权限不足

退出码含义0成功1泛型错误2无效命令参数3服务未运行(status命令专用)4权限不足4. 避免破坏Systemd的特性Systemd 是一个进程生命周期管理器,它需要直接跟踪服务的主进程(PID)。如果服务脚本不遵循规范,会导致Systemd无法正确管理服务状态(如判断是否运行、自动重启等)。4.1 禁止后台化进程4.1.1 错误写法

# 传统SysV脚本中常见的后台化方式/usr/bin/my_daemon --config /etc/my.conf &

4.1.2 问题

  • Systemd 会启动脚本,但脚本中的 & 会让 /usr/bin/my_daemon 在后台运行。
  • Systemd 只能监控到脚本自身(即Shell进程)的状态,而无法追踪真正的服务进程(my_daemon)。
  • 当Shell脚本执行完毕后,Systemd 会认为服务已退出,导致服务状态显示为 inactive (dead),即使my_daemon仍在运行。

4.1.3 正确写法

# 使用 exec 替换当前进程(Shell脚本进程被替换为服务进程)exec/usr/bin/my_daemon --config /etc/my.conf

4.1.4 原理

  • exec命令会让当前Shell进程直接被替换为my_daemon进程。
  • Systemd 可以追踪到 my_daemon 的PID,从而正确管理服务状态。

4.2 日志输出规范4.2.1错误写法

# 直接输出到控制台或文件echo"Starting service..."> /dev/console/usr/bin/my_daemon >> /var/log/my_service.log2>&1

4.2.2 问题

  • Systemd 默认通过 journald 集中管理日志,直接写入文件会导致日志分散,难以查询。
  • 若服务崩溃,Systemd 可能无法捕获崩溃前的最后日志。

4.2.3 原理

  • Systemd 会自动捕获服务的stdout/stderr 并写入 journald。
  • 可通过journalctl -u my_service 查看完整日志,无需手动管理日志文件。

5. 注册服务依赖SysV脚本需通过 LSB头部注释 声明依赖关系,帮助Systemd理解服务启动顺序和条件。这是SysV与Systemd兼容的关键!5.1 LSB头部详解

### BEGIN INIT INFO#Provides: my_service# 服务名称(唯一标识)#Required-Start:$network$syslog# 依赖的服务或系统设施#Required-Stop:$network$syslog# 停止时的依赖#Default-Start: 2345# 启用服务的运行级别#Default-Stop: 016# 禁用服务的运行级别#Short-Description: My Service# 简短描述#Description: Long description here.### END INIT INFO

5.1.1 关键字段Required-Start 服务启动前必须就绪的依赖项,例如:

  • $network 等待网络就绪;
  • $syslog 等待日志系统就绪;
  • nginx 等待$network服务启动;
  • docker.socket 等待Docker套接字就绪;
  • Default-Start/Default-Stop 定义服务在哪些运行级别自动启动或停止;
  • 2 3 4 5 多用户模式(无图形界面或图形界面);
  • 0 1 6 关机、单用户模式、重启。

5.2 依赖注册命令5.2.1 目的将LSB头部中的依赖关系转换为系统实际的启动链接(符号链接到 /etc/rcX.d/ 目录)。

Debian/Ubuntu:# 生成依赖链接 sudoupdate-rc.d my_service defaults
# 移除依赖链接sudoupdate-rc.d my_service remove

5.3 依赖不注册的后果假设 my_service 依赖网络,但未声明 $network:

  • SysV场景:服务可能在网络未就绪时启动,导致连接失败。
  • Systemd场景:systemd-sysv-generator 无法生成正确的依赖关系,服务可能并行启动,引发竞态条件。

79bde8c0-b3b0-11f0-8ce9-92fbcf53809c.png6. 总结

  • 避免后台化 → 让Systemd直接跟踪主进程。
  • 规范日志输出 → 信任Systemd的日志管理能力。
  • 声明依赖 → 通过LSB头部告诉Systemd“谁先谁后”。
  • 注册服务 → 确保依赖关系生效,服务按预期启动。
  • SysV脚本的“四不像”问题本质是 对Systemd机制的不理解。遵循上述规范,可最大限度兼容Systemd,同时为未来迁移到原生Systemd服务铺平道路。


79a40b4e-b3b0-11f0-8ce9-92fbcf53809c.jpg  创建并启用 SysV Init 脚本的完整流程

1. 创建 SysV Init 脚本的位置SysV Init 脚本必须放置在 /etc/init.d 目录下,这是所有 SysV 风格服务脚本的标准位置。Systemd 的兼容层(systemd-sysv-generator)会自动扫描此目录,将符合规范的脚本转换为 Systemd 服务单元。

2. 创建脚本的步骤

2.1 创建脚本文件使用文本编辑器(如 nano)在/etc/init.d/下创建脚本文件:

sudo nano/etc/init.d/my_service

2.2 编写脚本内容粘贴以下模板(需根据实际服务修改):

#!/bin/bash### BEGIN INIT INFO# Provides: my_service# Required-Start: $network $syslog# Required-Stop: $network $syslog# Default-Start: 2345# Default-Stop: 016# Short-Description: My Custom Service# Description: This service does something important.### END INIT INFO
# 服务主程序路径DAEMON="/usr/bin/my_daemon"NAME="my_service"
case"$1"instart)echo"Starting$NAME"exec$DAEMON;;stop)echo"Stopping$NAME"killall -9$DAEMON;;restart)$0stop$0start;;status)ifpidof -x"$DAEMON">/dev/null;thenecho"$NAMEis running"exit0elseecho"$NAMEis stopped"exit3fi;;*)echo"Usage:$0{start|stop|restart|status}"exit1esac
exit0

3. 启用服务的两种方式3.1 传统 SysV 方法(兼容 Systemd)

# Debian/Ubuntusudoupdate-rc.d my_service defaults

3.2 Systemd 原生方法(推荐)

# 直接通过 Systemd 启用(等效于 update-rc.d)sudo systemctlenablemy_serviceSystemd 会自动生成符号链接:Created symlink /etc/systemd/system/multi-user.target.wants/my_service.service → /lib/systemd/system/my_service.service.

4. 验证脚本兼容性4.1 检查 LSB 头部合规性

# Debian/Ubuntusudoinsserv -n my_service

输出应无错误,显示依赖关系已解析。4.2 查看 Systemd 生成的单元文件

# 查看生成的 .service 文件systemctl cat my_service输出示例:# /run/systemd/generator.late/my_service.service# Automatically generated by systemd-sysv-generator
[Unit]Documentation=man:systemd-sysv-generator(8)SourcePath=/etc/init.d/my_serviceDescription=My Custom ServiceAfter=network.target syslog.target
[Service]Type=forkingRestart=noTimeoutSec=5minIgnoreSIGPIPE=noKillMode=processGuessMainPID=noRemainAfterExit=yesExecStart=/etc/init.d/my_service startExecStop=/etc/init.d/my_service stopExecReload=/etc/init.d/my_service restart

5. 管理服务

# 启动服务sudosystemctl start my_service

# 查看状态systemctlstatus my_service

# 停止服务sudosystemctl stop my_service

# 重启服务sudosystemctl restart my_service

6. 关键注意事项6.1 避免冲突配置如果服务已存在 Systemd 原生单元文件(如/lib/systemd/system/my_service.service),需删除或禁用它,否则 SysV 脚本可能被忽略。6.2 禁用传统服务干扰停止并禁用旧版networking服务(如果存在):

systemctl stop networkingsudo systemctldisablenetworking

6.3 日志输出规范确保服务进程的日志输出到 stdout/stderr,而非直接写入文件。Systemd 会通过 journalctl 捕获日志:

journalctl-u my_service -f

7. 总结步骤命令/操作目的创建脚本sudo nano /etc/init.d/my_service定义服务行为赋予执行权限sudo chmod +x /etc/init.d/my_service确保脚本可执行启用服务sudo systemctl enable my_service设置开机自启验证 Systemd 兼容性systemctl cat my_service检查自动生成的单元文件管理服务生命周期systemctl start/stop/restart my_service控制服务运行状态通过遵循上述步骤,您可以在 Systemd 系统中安全地使用 SysV Init 脚本,同时享受 Systemd 的监控和管理功能。但长期来看,仍建议迁移到原生 Systemd 服务单元(.service 文件),以充分利用资源控制、依赖管理和自动重启等高级特性。
79d0d8d6-b3b0-11f0-8ce9-92fbcf53809c.jpg  EM系列储能边缘智能网关

EM系列储能边缘智能网关是ZLG致远电子专为新能源储能系统设计的一款高性能、多接口通讯管理设备,可在储能系统应用中作为边缘EMS(能源管理系统)总控、通讯管理机、规约转换器或BAU(电池管理总控)使用。该系列产品集成丰富的外设接口,支持各类BMS、PCS、空调、电表、屏显等设备的通讯传输,且软件上支持RT-Linux、Ubuntu等操作系统,支持IEC-61850/IEC-104/EtherCAT等专用协议,可广泛满足各类储能系统的本地能源管理应用需求。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5188

    文章

    20177

    浏览量

    329271
  • 脚本
    +关注

    关注

    1

    文章

    407

    浏览量

    29076
  • Ubuntu系统
    +关注

    关注

    0

    文章

    93

    浏览量

    4531
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Linux使用Systemd管理进程服务

    systemd是目前Linux系统主要的系统守护进程管理工具,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面init也仅仅是执行启动
    发表于 11-28 09:07 768次阅读

    如何在 Linux 从 NetworkManager 切换为 systemd

    今天,大部分主流 Linux 发行版都已经采用了 systemd 作为默认的初始化(init)系统。  正如其作者所说,作为一个 "从未完成、从未完善、但一直追随技术进步" 的系统
    发表于 11-25 10:08

    脚本引擎编写

    tcl脚本小白,我现在需要编写一个脚本引擎,目前已经建立好了自己的一套指令系统,需要能使用这个脚本引擎将我记事本编写的程序翻译成机器码,换句
    发表于 03-19 16:16

    现代 Linux 的五大初始化系统(1992-2015)

    更加高效和完美的初始化系统。尽管这些替代方案都超越了 SysV 并提供了更多新特性,但它们仍然和原始 SysV 初始化脚本保持兼容。2. SystemDSystemD 是一个 Linu
    发表于 10-23 14:28

    i.M8XMQ开发板如何通过Systemd服务实现应用自启

    飞凌OKMX8MQ-C开发板是基于ARM®Cortex-A53和Cortex-M4的内核,具有业界领先的音频、语音和视频处理功能。这次我们就来介绍一下如何通过systemd服务实现音频应用的自启
    发表于 04-25 15:22

    怎样写一个shell脚本以实现Android7.1.2源码的自动编译呢

    怎样写一个shell脚本以实现Android7.1.2源码的自动编译呢?
    发表于 03-04 06:32

    如何将imx8mpevk板的默认Systemd - Init Manager更改为Sysvinit?

    如何将 imx8mpevk 板的默认 Systemd - Init Manager 更改为 Sysvinit。是否更改了 build/conf/local.conf 文件 INIT
    发表于 03-15 06:42

    走进Linux之systemd启动过程

    的问题,systemd是Linux系统机器的另一种启动方式,宣称弥补了以传统Linux SysV init为基础的系统的缺点。
    发表于 04-27 19:14 3568次阅读

    Linux命令行与shell脚本编写

    Linux命令行与shell脚本编写
    发表于 01-11 16:50 4次下载

    编写一个点名器脚本

    目的:编写一个脚本,可以将准别好的名字合集的.txt传入脚本,然后每次随机显示一个人的姓名
    的头像 发表于 11-06 12:41 1042次阅读
    <b class='flag-5'>编写</b>一个点名器<b class='flag-5'>脚本</b>

    shell实例三(编写批量修改扩展名脚本)

    实现功能: 编写批量修改扩展名脚本,如批量将 txt 文件修改为 doc 文件 执行脚本时,需要给脚本添加位置参数
    的头像 发表于 11-09 09:35 1245次阅读
    shell实例三(<b class='flag-5'>编写</b>批量修改扩展名<b class='flag-5'>脚本</b>)

    Linux项目开发,你必须了解Systemd服务!

    1.Systemd简介Systemd是什么,以前linux系统启动init机制,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面
    的头像 发表于 06-18 17:59 1502次阅读
    Linux项目开发,你必须了解<b class='flag-5'>Systemd</b>服务!

    Systemd是什么?Systemd Service配置文件详解

    Systemd是什么,以前linux系统启动init机制,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面init也仅仅是执行启动
    的头像 发表于 07-22 18:03 2891次阅读

    systemd journal收集日志的三种方式

    随着 systemd 成了主流的 init 系统,systemd 的功能也在不断的增加,比如对系统日志的管理。Systemd 设计的日志系统好处多多,这里笔者就不再赘述了,本文笔者主要
    的头像 发表于 10-23 11:50 1330次阅读
    <b class='flag-5'>systemd</b> journal收集日志的三种方式

    技术分享】Systemd原生服务配置最佳实践(下)

    上期我们说到sysv的规范,创建以及示例,那么我们今天就来讲讲Systemd的原生服务配置。为何要迁移到Systemd原生服务?尽管规范化的SysV
    的头像 发表于 10-29 11:40 289次阅读
    【<b class='flag-5'>技术</b>分享】<b class='flag-5'>Systemd</b>原生服务配置最佳实践(下)