Linux Day21——systemctl操作 ---type: learning-notetitle: Linuxsystemctl 操作与起不来初探date: 2026-10-14description: 自己写 unit 文件并让它跑起来daemon-reload 的两种情形只改描述 vs 改启动命令start/stop/restart 与 is-activestatus 一屏怎么读三个符号、Loaded 与 Active 两个轴、TriggeredBy、Durationenable/disable 建删软链Typesimple 导致的start 不报错但服务 failed从 failed 往下第一跳status 底部日志 / journalctl -u退出码表LSB 那套、0/3/4 的分工收拾现场三层清理---# 2026-10-14 学习笔记 GitHubhttps://github.com/AR-firefly## 笔记区### 核心观点**一、最小 unit 文件与它放哪**- 一个能跑起来的服务文件里最少三行每段一行ini[Unit]DescriptionHello Test Service[Service]ExecStart/bin/sleep infinity[Install]WantedBymulti-user.target| 行 | 写在哪段 | 管什么 || -------------- | ----------- | ------------------------------------------------------------------------------------------- || Description | [Unit] | 给**人**看的名字systemctl status 第一行显示它。**随便填** || ExecStart | [Service] | 启动时**跑哪个程序****绝对路径** 参数。/bin/sleep infinity 永远睡进程不会自己退 || WantedBy | [Install] | enable 时**挂到哪个 target 下面**。**必须填系统里真有的 target 名**带 .target |- **放哪**/etc/systemd/system/ —— 回扣 10-13 讲的三层目录这层是**管理员**放的优先级最高。- **WantedBy 填错会怎样**实测两种- 填 World**不带后缀**→ enable 直接报 **Failed to enable unit: Invalid unit name World**退出码 1- 填 World.service**带后缀但系统里没这个 unit**→ enable **不报错**、照样建 World.service.wants/ 目录**但多一句警告** is added as a dependency to a non-existent unit —— **开机根本没人读那个目录等于白干**- 填 multi-user.target真实存在→ 正常- **multi-user.target 是哪来的****系统自带的**不是谁写的。- systemctl list-unit-files multi-user.target → 状态是 static- systemctl show multi-user.target -p FragmentPath → /usr/lib/systemd/system/multi-user.target**发行版装包时装的**那层- **能填哪些 target** → systemctl list-units --typetarget本机 23 个。服务器上的常驻服务基本都挂 multi-user.target。**二、怎么验证自己写的东西两件工具**| 要验什么 | 用什么 | 怎么判 || -------------------------- | ---------------------------------------------------------- | ---------------------------------------------------- || **文件写得对不对**语法 | systemd-analyze verify /etc/systemd/system/hello.service | **没输出 合法**有输出它会带**文件名:行号**指出来 || **服务真不真跑得起来** | 先 start再 is-active / status | 见下面点三、点四 |- **硬判据是退出码**echo $? —— **0 成功非 0 失败**。- 实测对照把 ExecStart 写成小写 Execstart错误拼法verify 直接报/tmp/bad.service:5: Unknown key Execstart in section [Service], ignoring.bad.service: Service has no ExecStart, ExecStop, or SuccessAction. Refusing.Unit bad.service has a bad unit file setting.退出码 1**三、daemon-reload —— 两种情形不一样实测分出**- **它干什么**man 1 systemctl 原文Reload the systemd manager configuration. This will rerun all generators, reload all unit files, and recreate the entire dependency tree. —— 让 systemd 把磁盘上的单元文件**整个重读一遍**、依赖树重搭。- **它为什么存在**systemd 把配置**加载进内存**跑磁盘上改了内存里那份就过时了。- ⭐ **实测分两种情形**差别在改动影响不影响行为| 改了什么 | 不跑 daemon-reload 会怎样 || -------------------------------- | ----------------------------------------------------------------------------------------------------------- || Description**只影响显示** | systemctl show -p Description **直接看到新值** || **ExecStart影响怎么跑** | ⚠️ systemd **警告** Run systemctl daemon-reload to reload units.而且 **restart 之后跑的还是旧程序** |- **另一个实测**服务**没在跑**时改 ExecStart不 reload 直接起**跑的是新值**。- **所以准确说法**daemon-reload 是把**内存里那份**换成磁盘上最新的**当 systemd 要用内存那份时**服务已在跑不 reload 就用旧的。手册也承认它不是唯一入口 —— man 5 systemd.unit:372Use systemctl daemon-reload or an equivalent command to reload unit configuration while the unit is already …**或一条等价的命令**。**四、start / stop / restart 一个问句**| 命令 | 干什么 | 要 sudo 吗 || ---------------------------- | ---------------------------- | ------------ || systemctl start 服务 | **现在开始跑** | 要 || systemctl stop 服务 | **现在停下** | 要 || systemctl restart 服务 | **停再起** stop start | 要 || systemctl is-active 服务 | **问一句现在在不在跑** | 不要 |- 前三条**改系统状态**所以 sudois-active 只是问。- **restart 和 start 的差别**服务**已经在跑**时start 什么都不做、restart 才先停再起服务**已经停了**时两条**效果一样**。- 实测start / stop / restart **成功时都没有输出**退出码都是 0。**五、读懂 systemctl status 那一屏**- **它和 show 的分工**man 1 systemctlThis function is intended to generate human-readable output. If you are looking for computer-parsable output, use show instead. —— **status 给人看show 给机器看**。- **它只显示运行时状态**在跑 → 当前这次没跑 → **最近那次**所以没跑的服务底下还能看到上次的起停记录。- **第一行开头那个符号**三个实测| 符号 | 状态 || ---------- | -------------------- || ● 实心圆 | **active**在跑 || ○ 空心圆 | **inactive**没跑 || × 叉 | **failed**失败了 |- **分段读**以跑着的为准● hello.service - Hello Test Service V1 ← 第一行符号 名字Loaded: loaded (/etc/systemd/system/hello.service; disabled; preset: enabled)Active: active (running) since ...; 476ms agoInvocation: 78229a74bf5b480eb3e8d336150a4d4bMain PID: 11605 (sleep)Tasks: 1 (limit: 9127)Memory: 1.3M (peak: 1.7M)CPU: 11msCGroup: /system.slice/hello.service└─11605 /bin/sleep infinityOct 14 13:06:27 AR-firefly systemd[1]: Started hello.service - Hello Test Service. ← 日志尾巴- **Loaded: 行 —— 答开机会不会自动起**loaded 单元文件加载成功括号里第一段 **文件路径****disabled** 开机不会自动起preset: enabled 发行版预设值。- **Active: 行 —— 答现在在不在跑**前半是**总状态**active / inactive / failed括号里是**细分状态**running / dead / exited。- **两个轴必须分开问** —— 它俩**真的会不一样**。实测 snapdis-enabled enabled、is-active inactive10-10 起来过、跑了 18 秒、退出了之后再没起。- **TriggeredBy:** 这个单元**被谁触发**snapd 是被 snapd.socket 触发的。**Duration:** 上次那趟**跑了多久**。- **status 默认只显示 10 行**manBy default, this function only shows 10 lines of output and ellipsizes lines to fit in the terminal window.—— **别当它是全部**可以用 --lines / --full 改。**六、enable / disable —— 管的是链接不是开关**- **enable 干的事就一件按 [Install] 段的说明去 .wants/ 目录里建一条符号链接。**- **enable 完服务不会自己跑**手册this does not have the effect of also starting any of the units being enabled。- **disable 把那条链接删掉**一对反义词。- **怎么当场看到证据ls 前后对比**今天的主产出$ ls /etc/systemd/system/multi-user.target.wants/ | wc -l20$ sudo systemctl enable hello.serviceCreated symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.$ ls -la /etc/systemd/system/multi-user.target.wants/ | grep hellolrwxrwxrwx 1 root root 33 Oct 14 22:50 hello.service - /etc/systemd/system/hello.service$ sudo systemctl disable hello.serviceRemoved /etc/systemd/system/multi-user.target.wants/hello.service.$ ls -la /etc/systemd/system/multi-user.target.wants/ | grep hello无输出- 两条都要 sudo在改 /etc/ 下的文件。**七、造一个起不来的服务**- **start 一个起不来的服务命令本身可能一点都不报错**$ sudo systemctl start bad.service$ echo $?0 ← 退出码 0一点动静都没有$ systemctl is-active bad.servicefailed ← 其实根本没起来- **为什么不报错**[Service] 段里没写 Type默认是 **Typesimple**man 5 systemd.serviceIf not set, the default is Typesimple.。- simple 的意思**命令一拉起来就算启动完成** —— systemd 把进程拉起来就回报成功**不等它跑起来看看**。- **所以****不能靠start 没报错判断服务起没起**得**另外问一句**is-active / status。**八、从 failed 往下第一跳**- status 一屏里的 failed 现场实测× bad.service - Broken Test ServiceLoaded: loaded (/etc/systemd/system/bad.service; disabled; preset: enabled)Active: failed (Result: exit-code) since Wed 2026-10-14 23:03:36 CST; 1min 52s agoProcess: 15298 ExecStart/nonexistent/program (codeexited, status203/EXEC)Main PID: 15298 (codeexited, status203/EXEC)Oct 14 23:03:36 AR-firefly systemd[1]: Started bad.service - Broken Test Service.Oct 14 23:03:36 AR-firefly (program)[15298]: bad.service: Unable to locate executable /nonexistent/program: No such file or directoryOct 14 23:03:36 AR-firefly (program)[15298]: bad.service: Failed at step EXEC spawning /nonexistent/program: No such file or directoryOct 14 23:03:36 AR-firefly systemd[1]: bad.service: Main process exited, codeexited, status203/EXECOct 14 23:03:36 AR-firefly systemd[1]: bad.service: Failed with result exit-code.- **关键行两处**- **Active: failed (Result: exit-code)** —— Result: 是**失败原因**字段- **Process: … (codeexited, status203/EXEC)** —— 203 是**专门的码**含义见下面退出码表- **底下那几行日志直接说出原因**Unable to locate executable … / Failed at step EXEC …。- **这段日志是从 journal 抓的**要专门查一个服务的日志用 **journalctl -u 服务**-u unit它比 status 底部**全**。- **systemctl is-failed 服务** 专门问它是不是失败状态。### 关键方法/流程**退出码这一套今天专门展开的**- **通用规律****0 成功非 0 失败**。- **但失败具体是几每个命令自己定** —— 查法固定man 命令 搜 **EXIT STATUS**。- 实测的几个| 命令 | 号码 || ---------------------- | ------------------------------- || true / false | 0 / 1 || ls文件不存在 | 2 || grep一行都没选中 | 10 找到了2 出错 || systemctl | 见下表 |- **systemctl 那套来自 LSB 标准**man 1 systemctlsystemctl uses the return codes defined by LSB, as defined in LSB 3.0.0| 值 | LSB 里的说法 | systemd 拿去表示 || ------- | ---------------------------------------------- | --------------------------------- || 0 | program is running or service is OK | **unit is active** || 1 | program is dead and /var/run pid file exists | unit not failedis-failed 用 || 2 | program is dead and /var/lock lock file exists | unused || **3** | **program is not running** | **unit is not active** || 4 | program or service status is unknown | **no such unit** |- **is-active 是特例**它的退出码**不是命令成没成是答案** —— 0 在跑非 0 没在跑。- **两个 inactive 要靠退出码分****3** 单元在、没在跑**4** 压根没这个单元。- **想一眼看出这东西没了**用 **is-enabled** —— 它对不存在的单元直接回 not-found。**收拾现场实验做完要收回**- **三层顺序有讲究**| 清什么 | 用什么 | 为什么要单独清 || ------------------- | ------------------------------------- | --------------------------------------------------------- || **失败状态** | systemctl reset-failed 服务 | 它记在 systemd 的运行时对象里**删单元文件不会自动抹掉** || **单元文件** | rm /etc/systemd/system/名.service | 留着的话下次谁 start 它会**真起这个假服务** || **让 systemd 忘掉** | systemctl daemon-reload | 重读目录 |- **reset-failed 凭什么不清就不消失**man 5 systemd.unit:666CollectMode 那段… failed units are not unloaded until the user invoked systemctl reset-failed on them to reset the failed state, or an equivalent command. —— systemd 有一套**不用了就从内存里收走**的垃圾回收机制**failed 状态会挡住不收**所以那条记录一直留着**得 reset-failed 才放它走**。- **为什么必须清干净**①留着 failedsystemctl --failed 一直列它**真出故障时干扰判断**②留着文件假服务可能被真起起来。### 实战记录**① 自己写的服务跑起来了**$ sudo systemctl start hello.service$ systemctl is-active hello.serviceactive$ echo $?0**② enable 真的建了链接**$ sudo systemctl enable hello.serviceCreated symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.$ ls -la /etc/systemd/system/multi-user.target.wants/ | grep hellolrwxrwxrwx 1 root root 33 Oct 14 22:50 hello.service - /etc/systemd/system/hello.service**③ 起不来的服务start 说成功、其实 failed**$ sudo systemctl start bad.service$ echo $?0$ systemctl is-active bad.servicefailed**④ 从 failed 往下查日志直接说出原因**$ journalctl -u bad.service --no-pagerOct 14 23:03:36 AR-firefly systemd[1]: Started bad.service - Broken Test Service.Oct 14 23:03:36 AR-firefly (program)[15298]: bad.service: Unable to locate executable /nonexistent/program: No such file or directoryOct 14 23:03:36 AR-firefly (program)[15298]: bad.service: Failed at step EXEC spawning /nonexistent/program: No such file or directoryOct 14 23:03:36 AR-firefly systemd[1]: bad.service: Main process exited, codeexited, status203/EXECOct 14 23:03:36 AR-firefly systemd[1]: bad.service: Failed with result exit-code.---## 线索区学完后合上材料自问自答**Q: 一个最小 unit 文件三段各写一行分别是什么**A: [Unit] 的 Description给人看的名字、[Service] 的 ExecStart跑哪个程序、[Install] 的 WantedByenable 时挂到哪个 target。**Q: WantedBy 能随便填吗**A: 不能。**必须填系统里真有的 target 名**带 .target。填 World没后缀→ enable 直接报错填 World.service有后缀但没这个 unit→ 不报错但**等于白填**开机没人读那个目录。**Q: multi-user.target 是哪来的**A: **系统自带的**FragmentPath/usr/lib/systemd/system/multi-user.target发行版装包时装的。看有哪些systemctl list-units --typetarget。**Q: 怎么验证自己写的 unit 文件对不对**A: systemd-analyze verify 文件路径 —— **没输出 合法**有输出会带文件名:行号。硬判据看 echo $?0 过。**Q: daemon-reload 干什么**A: 让 systemd 把磁盘上的单元文件**整个重读一遍**换掉内存里那份过时的。**Q: 改了 unit 文件不跑 daemon-reload会怎样**A: **分两种**改 Description 这种**只影响显示**的show 直接看到新值改 **ExecStart** 这种**影响行为**的systemd 会**警告**要 reload而且 restart **还是跑旧程序**。**Q: start / stop / restart 各管什么**A: start 现在开始跑stop 现在停restart 停再起。服务已经停着时start 和 restart 效果一样。**Q: 怎么确认一条 start 真的生效了**A: **不能只看它没报错、也不能只看 echo $?**那说的是命令没报错。要问服务本身systemctl is-active 服务。**Q: status 第一行开头那个圆点是干什么的**A: 标状态● active、○ inactive、× failed。**Q: Loaded: 和 Active: 分别回答什么问题**A: Loaded: 答**开机会不会自动起**里面那个 enabled/disabledActive: 答**现在在不在跑**。两个轴**真的会不一样**实例 snapdenabled inactive。**Q: enable 到底干了什么**A: 就**建一条符号链接**按 [Install] 段的说明建到 .wants/ 目录里。**它不会顺带把服务跑起来**。**Q: 怎么当场证明 enable 生效了**A: ls **前后对比** —— 拿 .wants/ 目录的条数20 → 21 → 20或直接 grep 那条链接。**Q: 为什么 start 一个写坏的服务命令却不报错**A: 因为没写 Type默认是 **Typesimple** —— 命令一拉起来就算启动完成systemd 不等它跑起来看看。**Q: 服务 failed 了往哪儿查为什么**A: status 底部的日志尾巴Result: 行 那几行日志或者用 journalctl -u 服务 拉全。**Q: status 底下的日志和 journalctl -u 出来的什么关系**A: status 底部是从 journal 抓的最近几条**默认只显示 10 行**journalctl -u 给你全部。**Q: 退出码 3 和 4 差在哪**A: 都是 is-active 回的 inactive**3** 单元在、没在跑**4** 压根没这个单元。想直接看存不存在用 is-enabled回 not-found。**Q: 实验做完为什么删了文件还要跑 reset-failed**A: 因为**失败状态记在 systemd 的运行时对象里**删文件不会抹掉。failed 状态会挡住 systemd 的垃圾回收man 5 systemd.unit:666所以它一直留着 —— 要清得 reset-failed或 stop/restart。---## 总结50字以内用自己的话概括今天学到了什么自己写 unit 文件让它跑起来enable 建链接、start 是开关status 两个轴分开看start 不报错≠服务起来了Typesimple 的坑出 **failed** 先看日志。---## 复习卡片| 概念 | 必学/了解 | 一句话 | 场景 || ------------------------------------------- | --------- | ----------------------------------------------------------------- | -------------------- || /etc/systemd/system/ | 必学 | 管理员放的单元文件目录优先级最高 | 自己写服务 || [Unit] / [Service] / [Install] | 必学 | 是什么 / 怎么跑 / 装的时候怎么挂 | 三段 || Description | 必学 | 给人看的名字随便填 | [Unit] || ExecStart | 必学 | 跑哪个程序绝对路径 参数 | [Service] || WantedBy | 必学 | enable 时挂到哪个 target**要填真有的** | [Install] || multi-user.target | 必学 | 多用户模式那一组**系统自带**的 | 服务器服务常挂它 || systemctl list-units --typetarget | 必学 | 看系统有哪些 target | 挑 WantedBy 的值 || systemd-analyze verify | 必学 | 检查 unit 文件写得对不对 | 写完先验 || echo $? | 必学 | 上一条命令的退出码0 成功 | 判成败 || 退出码 EXIT STATUS 段 | 必学 | 每个命令的号码表在这 | man 命令 || LSB 退出码表 | 必学 | systemctl 借的那套0/1/3/4 | 读 is-active 的码 || daemon-reload | 必学 | 让 systemd 重读单元文件 | 改了配置 || start / stop / restart | 必学 | 管现在跑不跑 | 点三 || is-active | 必学 | 问现在在不在跑退出码即答案 | 验证 || is-enabled | 必学 | 问开机会不会起不存在时回 not-found | 另一个轴 || is-failed | 必学 | 问它是不是失败状态 | 排查 || status | 必学 | 人读版一屏默认 10 行 | 看现场 || show | 必学 | 机器读版293 行属性 | 脚本/精确取值 || ● / ○ / × | 必学 | active / inactive / failed | status 第一行 || Loaded: | 必学 | 答开机会不会自动起 | status || Active: | 必学 | 答现在在不在跑 | status || 两个轴 | 必学 | 开机与当下是两件事要分开问 | snapd 那个实例 || TriggeredBy: / Duration: | 必学 | 被谁触发 / 上次跑了多久 | status || enable / disable | 必学 | 建 / 删 .wants/ 里那条软链 | 开机自启 || .wants/ 目录 | 必学 | 装想要这些的链接 | enable 的产物 || Type默认 simple | 必学 | 怎么算起来了不写就是拉起来就算成 | start 不报错的根因 || Result: exit-code | 必学 | 失败原因字段 | status 的 failed || status203/EXEC | 必学 | 卡在 exec 这一步程序没找到 | 排查 || journalctl -u | 必学 | 专门拉某个服务的日志 | 第一跳 || reset-failed | 必学 | 清失败状态不然它一直留着 | 收拾现场 || not-found | 必学 | is-enabled 对不存在单元的回答 | 确认删干净 || sudo | 必学 | 改状态要 root问状态不要 | 全程 || nano | 必学 | 终端编辑器CtrlO 存、CtrlX 退 | 写文件 || Type 其余 7 种取值 | 了解 | exec/forking/oneshot/dbus/notify/notify-reload/idle | 用到再查 || mask | 了解 | 比 disable 更狠连手动 start 都不行 | 10-13 提过 || StartLimitIntervalSec / StartLimitBurst | 了解 | 启动频率限流反复失败会被拒 | reset-failed 能解 |---## 旧知识回收今天暴露出来的| 概念 | 一句话 | 出处 || ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------- || apt 与 dpkg 两层分工 | dpkg 在下层只认本地 .deb、不上网、不算依赖apt 在上层上网、算依赖、下载交给 dpkg 装。**本机装了什么两个都看得到** | 抽考 09-29 第 2 问答应该是 apt 看得到吧 || dpkg -l 状态位 | 头三行是字母表第 1 位 Desired、第 2 位 Status、第 3 位 Err。ii 装着的rc 卸了但配置还在 | 抽考 09-29 第 3 问答用什么命令看不知道只知道用 ls || 孤儿包与 autoremove | 当初被自动装上、现在没人依赖的包apt **只提示不动手**没人依赖 ≠ 用不着删不可逆 | 抽考 09-29 第 4 问答不知道 |---## 今日产出验收对照当天教学卡的 7 条产出逐条判定| # | 产出 | 判定 | 证据 || --- | ------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ || 1 | 写出能跑起来的最小 .service、说清三行各管什么 | 做得出 讲得清 | 亲手写了 hello.service默写时 Execstart 大小写错、被指出后改对三段用途答对 || 2 | 说清 daemon-reload 干什么 | 做得出 讲得清 | 自己实测出不跑它也更新又实测出改 ExecStart 不跑不生效答出自己更新一手配置文件 || 3 | 跑通 start / stop / restart is-active 验证 | 做得出 讲得清 | 三条都跑、is-active 输出对答出echo $? 看的是命令得吃没有不是服务器跑起来没有 || 4 | 读懂 status 三段、说清 Loaded: / Active: 各答什么 | 做得出 讲得清 | 读了 hello / bad / snapd 三个答出两个轴找出 snapd 这个两轴不一致的实例 || 5 | 用 ls 前后对比证明 enable 建链接、disable 删链接 | 做得出 讲得清 | 20 → enable → 21 → disable → 20全程亲手跑答出enable 是建链接开机起start 是现在跑 || 6 | 造出真起不来的服务、读出原因、说清 start 为什么不报错 | 做得出 讲得清 | 亲手建 bad.service、start 退出码 0、is-active 回 failedstatus 读出 status203/EXEC、Typesimple 说出根因 || 7 | 把现场收拾干净 | 做得出 讲得清 | reset-failed → ls → rm → daemon-reload 三步亲手跑核对目录回到 13 条、失败单元 0 |