当服务器开始出现异常,显然有什么地方不对劲,直接运行 systemctl status 会输出一大堆文本却给不出任何有用的信息。
更快的做法是问 systemd 一个简单的问题:到底哪些服务失败了? 让它用两行代码而不是几百行来回答。
说明:systemd 是负责启动你的机器并管理所有后台服务的 init 系统,而 systemctl 是你在终端中用来与 systemd 交互的命令。
1.systemctl list-units --failed 究竟做了什么
systemctl list-units 命令会列出 systemd 当前跟踪的所有活动单元(unit),这里的"单元"就是 systemd 对其管理的对象(如服务、挂载点或定时器)的统称。
默认情况下,这个列表又长又杂,因为它包含了所有正常运行的内容。--failed 参数会将列表过滤为只显示处于 failed 状态的单元,也就是那些尝试启动或保持运行但未能成功的服务。
它不会告诉你失败的原因,也不会自动修复任何问题,但它能精准指向你需要进一步调查的那个服务名称。可以把它看作一个分诊工具,而非诊断工具。
这个命令的最简形式不需要任何参数,直接输入并读取输出即可:
systemctl list-units --failed
输出示例:
UNIT LOAD ACTIVE SUB DESCRIPTION
● nginx.service loaded failed failed A high performance web server
● mysql.service loaded failed failed MySQL Community Server
LOAD = 反映单元定义是否被正确加载
ACTIVE = 高层级的单元激活状态,即 SUB 的概括
SUB = 低层级的单元激活状态,具体取值取决于单元类型
共列出 2 个已加载单元。
两个服务失败了:nginx 和 mysql。每行开头的红点是 systemd 用来直观标记失败单元的方式。如果输出显示 0 loaded units listed,说明系统一切正常,没有服务损坏。
如果看到 Permission denied,说明你忘了加 sudo 前缀。sudo 命令会以 root 权限执行后面的命令,而 systemd 需要这个权限才能读取完整的单元状态。
2.仅过滤失败的服务
默认情况下,--failed 会包含所有类型的单元:套接字(socket)、定时器(timer)、挂载点(mount)和服务(service)都混在一起。当在故障期间通常只关心服务时,可以加上 --type=service 过滤条件:
sudo systemctl list-units --failed --type=service
输出:
UNIT LOAD ACTIVE SUB DESCRIPTION
● nginx.service loaded failed failed A high performance web server
共列出 1 个已加载单元。
现在输出仅限于失败的服务,这在实际故障处理中几乎总是我们想要的。
注意: 初学者常犯的错误是输入 --type=services(末尾带 s),这会报错 Invalid unit type,正确的值是不带复数的单数形式 service。
3.查找 Linux 中服务失败的原因
拿到失败服务列表后,下一步就是查明每个服务失败的原因。可以从列表中获取服务名称,直接运行 systemctl status,或者让 xargs 帮你一次性获取所有失败服务的状态。
xargs 命令接收管道左侧的输入,并将其转换为右侧命令的参数,这正是在失败服务列表动态变化时所需要的。
sudo systemctl status nginx.service
输出:
× nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Wed 2026-05-04 07:14:22 UTC; 3min ago
Process: 4821 ExecStartPre=/usr/sbin/nginx -t -q (code=exited, status=1/FAILURE)
May 04 07:14:22 web01 nginx[4821]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
最后一行日志才是真正的答案:端口 80 已被其他进程占用,这就是 nginx 无法启动的原因。如果 status 输出截断了日志行,可以加上 --no-pager -l 强制显示完整文本,其中 -l 防止输出被省略号截断,--no-pager 则跳过会吞掉输出末尾的 less 分页器。
当多个服务同时失败,你想一次性获取所有状态时,可以将 list-units 的输出通过管道传给 xargs,让后者将服务名称喂给 systemctl status。
管道中的每个部分都有其特定作用:
systemctl list-units --failed --no-legend --plain —— 只输出失败单元的名称,并去掉表头和状态点awk '{print $1}' —— 提取第一列,即单元名称xargs sudo systemctl status --no-pager —— 将这些名称作为参数一次性传给 systemctl status
systemctl list-units --failed --no-legend --plain | awk '{print $1}' | xargs sudo systemctl status --no-pager
输出:
× nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Wed 2026-05-04 07:14:22 UTC; 3min ago
Process: 4821 ExecStartPre=/usr/sbin/nginx -t -q (code=exited, status=1/FAILURE)
May 04 07:14:22 web01 nginx[4821]: nginx: [emerg] bind() to 0.0.0.0:80 failed
× mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Wed 2026-05-04 07:15:01 UTC; 2min ago
Process: 4902 ExecStart=/usr/sbin/mysqld (code=exited, status=1/FAILURE)
May 04 07:15:01 web01 mysqld[4902]: [ERROR] Could not open file '/var/log/mysql/error.log'
两个失败服务的报告依次输出:nginx 是端口冲突,mysql 是日志文件权限问题。这些信息足够让两个团队成员分工修复,无需重新运行任何命令。
注意: 初学者常犯的错误是忘记加 --no-pager,这会导致 xargs 为每个服务调用 less 分页器,迫使每次都要按 q 退出。
4.统计 Linux 中失败服务的数量
对于健康检查和监控脚本,需要的是一个可以和零比较的数字,而不是一张给人看的表格。使用 --no-legend 去掉表头和页脚,然后通过管道传给 wc -l 统计剩余行数。
systemctl list-units --failed --no-legend --plain | wc -l
输出:
2
两个失败单元,这样可以在 cron 任务、监控代理或 shell 脚本中据此发出告警。
常见错误是忘记 --plain,把彩色状态点也算作行的一部分。这对 wc -l 来说仍然有效,但如果你后续想用 awk 解析单元名称就会出问题。
5.显示所有失败的服务(包括已卸载的)
默认情况下,list-units 只显示 systemd 正在主动跟踪的单元,这可能会遗漏那些失败得过于严重以至于被卸载的服务。加上 --all 可以包含它们,再配合 --state=failed 实现同样的过滤效果:
sudo systemctl list-units --all --state=failed
输出:
UNIT LOAD ACTIVE SUB DESCRIPTION
● nginx.service loaded failed failed A high performance web server
● mysql.service loaded failed failed MySQL Community Server
● apt-daily-upgrade.timer loaded inactive dead Daily apt upgrade activities
--all 会引入那些已加载但不活动的单元,这有时能帮你发现一个卡住的定时器或一个悄悄停止触发的套接字。
常见错误是混淆 --state=failed 和 --failed,在这种情况下它们的作用相同。但 --state= 还可以接受许多其他值,如 active、inactive、activating,所以当你熟悉之后,它是更灵活的选择。
6.systemctl 常用参数
下面几个参数经常用到,值得在下次故障时形成肌肉记忆:
| 参数 | 作用 |
|---|
--no-pager | |
--no-legend | |
--plain | |
--type=service | |
--state=failed | --failed |
7.总结
--failed 参数是排查故障服务器的最快方法,结合 --no-legend 和 --plain 后,可以安全地放入任何监控脚本中,无需担心后处理时的意外。
可以找一台测试机,打开终端运行:
systemctl list-units --failed
如果没有失败的服务,可以故意破坏一个服务来测试:
sudo systemctl stop nginx && sudo systemctl start test-unit-name
然后再次运行 systemctl list-units --failed,亲眼看看输出变化。