shutdown 命令详解与参数实测(Ubuntu 22.04)

以 Ubuntu 22.04(systemd 249)实测逐参数讲解 shutdown:now/+m/hh:mm 三种时间、-c 取消、-k 假广播、-h/-P/-H 真实关机、--no-wall、--show 缺失踩坑、/run/nologin 与 wtmp 留痕,并给出与 reboot/halt/poweroff/systemctl/init 0 的完整对比。

Linux命令Linux系统UbuntuUbuntu 22.04命令行systemd2026/10/16

shutdown 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 shutdown 的每一个参数与用法——now/+m/hh:mm 三种时间格式、-c 取消计划、-k 假广播、-h/-P/-H/-r 四种停机动作、--no-wall 静默关机,以及计划登记的查看方法(busctl)、/run/nologin 登录封锁机制、wtmp 停机留痕与非 root 越权行为,全部命令与回显已在 Ubuntu 22.04(systemd 249)环境实测通过,其中关机类参数均真实执行并记录了主机停机后的 wtmp 日志证据。

一、环境信息

本文所有命令均在以下环境实测,回显逐字照抄:

  • 操作系统:Ubuntu 22.04.5 LTS(PRETTY_NAME="Ubuntu 22.04.5 LTS")
  • 内核:6.8.0-138-generic,x86_64 架构
  • init 系统:systemd 249 (249.11-0ubuntu3.23),systemctl is-system-running 实测返回 running
  • shutdown 所属软件包:systemd 249.11-0ubuntu3.23
  • shutdown 真实身份:/usr/sbin/shutdown -> /bin/systemctl 符号链接(3.1 节实测确认)
  • 系统时区:UTC(date 输出带 UTC 后缀),下文回显中的时间均为系统本地时间
  • 执行身份:root
  • 演示目录:/root/demo/shutdown/
  • 广播消息统一以 pw-test: 开头,便于与系统消息区分

💡 说明:关机/重启类命令每次真实执行都会让主机停止运行,本文所有破坏性命令都真实执行过并记录了执行后系统的 wtmp 留痕(last -x 输出),因此部分小节的回显是「执行命令 → 主机停机 → 重新启动后查看日志」的完整闭环,读者在自己的测试机上复现时请提前保存工作内容。

二、命令概览

2.1 语法与测试数据

shutdown 用于安排系统停机、重启或挂起,支持立即执行与延时执行,并在停机前向所有登录用户广播警告消息。语法(来自实测 shutdown --help 首行)只有一种形态:

shutdown [OPTIONS...] [TIME] [WALL...]

三个位置的参数含义:

  • [TIME]:什么时候停机,实测支持三种格式——now(立即)、+m(m 分钟后,如 +5)、hh:mm(当天指定时刻,已过则次日执行);
  • [WALL...]:广播消息正文,可以带空格的多个单词,会随警告消息一起发给所有登录用户;
  • [OPTIONS...]:动作与行为选项,全部选项见 2.2 节。

不写 TIME 时,shutdown 默认按「1 分钟后关机」处理(即等价于 +1);不写任何选项时,默认动作为关机断电(等同 -P)。本文测试数据约定:延时统一用 +5、时刻统一用 10:30,广播消息统一以 pw-test: 开头,每个参数小节均可独立执行复现。

💡 技术拓展:Linux 系统层面的「停机」其实是三个不同动作,shutdown 只是调度它们的入口——

动作系统层含义对应 shutdown 选项典型用途
poweroff停止系统后切断电源(ACPI 断电)-P 或默认日常关机、下架服务器
halt停止 CPU 与系统服务,但保留通电状态-H极少用,需物理机现场操作
reboot停止系统后重新引导-r内核升级、维护窗口重启

现代系统上 shutdown 把动作委托给 systemd-logind 调度,systemd 再按动作类型走对应停机流程;三者在 systemd 上的语义差异详见 3.16 节对比表。本文主线采用默认动作(poweroff),这也是生产上 99% 的场景。

2.2 --help 全量输出(逐行照抄)

先看完整帮助,是逐参数实测的地图。以下为 shutdown --help 的完整实测输出:

$ shutdown --help
shutdown [OPTIONS...] [TIME] [WALL...]

Shut down the system.

Options:
     --help      Show this help
  -H --halt      Halt the machine
  -P --poweroff  Power-off the machine
  -r --reboot    Reboot the machine
  -h             Equivalent to --poweroff, overridden by --halt
  -k             Don't halt/power-off/reboot, just send warnings
     --no-wall   Don't send wall message before halt/power-off/reboot
  -c             Cancel a pending shutdown

See the shutdown(8) man page for details.

关键差异解读:动作三兄弟 -H/-P/-r 互斥,-h 是一个特殊的历史兼容参数——它默认等价于 --poweroff,但一旦同时给出 --halt 就被覆盖为挂起动作;-k 是唯一「不真停机」的参数;-c 专门用来取消已登记的计划。--no-wall 只影响广播消息,不影响停机动作本身。

2.3 版本信息

Ubuntu 22.04 的 shutdown 属于 systemd 软件包,实测版本信息如下:

$ systemctl --version
systemd 249 (249.11-0ubuntu3.23)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY -P11KIT -QRENCODE +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified

$ dpkg -l systemd | tail -1
ii  systemd        249.11-0ubuntu3.23 amd64        system and service manager

systemctl --version 的第一行就是 shutdown 实际运行的版本(249.11-0ubuntu3.23),后一行是编译特性开关。版本号很重要:3.5 节将实测确认 systemd 249 的 shutdown 不支持 --show 选项(更高版本才引入),查计划需用 busctl 替代方案。

三、参数逐项实测

3.1 先确认身份:shutdown 是 systemctl 的符号链接

systemd 时代的 shutdown 不是独立二进制,而是 systemctl 的符号链接。systemctl 运行时按 argv[0](程序被调用的名字)判定要执行的动作,这是理解四命令行为一致性的关键:

ls -l /usr/sbin/shutdown /usr/sbin/reboot /usr/sbin/halt /usr/sbin/poweroff

实测回显:

$ ls -l /usr/sbin/shutdown /usr/sbin/reboot /usr/sbin/halt /usr/sbin/poweroff
lrwxrwxrwx 1 root root 14 Oct 12 07:44 /usr/sbin/halt -> /bin/systemctl
lrwxrwxrwx 1 root root 14 Oct 12 07:44 /usr/sbin/poweroff -> /bin/systemctl
lrwxrwxrwx 1 root root 14 Oct 12 07:44 /usr/sbin/reboot -> /bin/systemctl
lrwxrwxrwx 1 root root 14 Oct 12 07:44 /usr/sbin/shutdown -> /bin/systemctl

💡 要点:

  1. 四个命令全部指向 /bin/systemctl,本质上是同一套代码的不同入口;因此 2.2 节 shutdown --help 显示的是 shutdown 专属的短帮助,而不是 systemctl 的长帮助——systemctl 按 argv[0] 识别了身份。
  2. 这也解释了为什么 systemctl --version 的版本就是 shutdown 的版本(2.3 节),以及为什么 shutdown 的停机日志与 systemctl 停机完全一致(同一流程)。
  3. dpkg -S /usr/sbin/shutdown 可确认归属(输出 systemd: /usr/sbin/shutdown),排障时可用于区分是 systemd 包还是 SysV 兼容包提供的同名命令。

3.2 +m:延时关机计划(shutdown +5)

+m 格式安排 m 分钟后停机。执行后命令会立即返回一行确认消息,计划由 systemd-logind 登记,而不是由 shutdown 进程驻留等待:

shutdown +5 'pw-test: check nologin file'
echo "退出码=$?"
ls -l /run/nologin
busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
shutdown -c 'pw-test: cancel again'

实测回显:

$ shutdown +5 'pw-test: check nologin file'
Shutdown scheduled for Fri 2026-10-16 09:54:56 UTC, use 'shutdown -c' to cancel.
$ echo "退出码=$?"
退出码=0
$ ls -l /run/nologin
ls: cannot access '/run/nologin': No such file or directory
$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
(st) "poweroff" 1792144496349858
$ shutdown -c 'pw-test: cancel again'

计划确认后,紧跟着命令的立即查看居然没有找到 /run/nologin——这不是没创建,而是 D-Bus 异步处理的竞态。等 2 秒后再看,文件已生成:

shutdown +5 'pw-test: nologin timing'
sleep 2
ls -l /run/nologin
cat /run/nologin
shutdown -c 'pw-test: cleanup'
sleep 1
ls -l /run/nologin

实测回显:

$ shutdown +5 'pw-test: nologin timing'
Shutdown scheduled for Fri 2026-10-16 09:56:52 UTC, use 'shutdown -c' to cancel.
$ sleep 2
$ ls -l /run/nologin
-rw-r--r-- 1 root root 121 Oct 16 09:51 /run/nologin
$ cat /run/nologin
System is going down. Unprivileged users are not permitted to log in anymore. For technical details, see pam_nologin(8).
$ shutdown -c 'pw-test: cleanup'
$ sleep 1
$ ls -l /run/nologin
ls: cannot access '/run/nologin': No such file or directory

💡 要点:

  1. 确认消息的格式固定为 Shutdown scheduled for <日期 时间>, use 'shutdown -c' to cancel.,其中时间由「当前时间 + 5 分钟」精确计算(两次实测分别得到 09:54:56 与 09:56:52)。
  2. busctl 查到的 (st) "poweroff" 1792144496349858 是二元组:动作类型 poweroff + 目标时刻的微秒级时间戳;计划被取消后该属性变为 (st) "" 0(见 3.4 节),这是 systemd 249 上查看计划的可靠手段。
  3. /run/nologin 的出现意味着计划距执行已不足 5 分钟(+5 恰好落在边界上,立即创建),新登录会被 PAM 的 pam_nologin 模块拒绝,root 不受影响;-c 取消计划时该文件被自动删除(取消后 ls 报 No such file or directory)。紧跟命令立即查看会撞上异步竞态(No such file or directory),脚本里确认文件状态请先 sleep 1~2。

3.3 hh:mm:指定当天时刻关机

hh:mm 格式安排在当天指定时刻执行;若该时刻已过,则安排到次日同一时刻。实测安排到当天 10:30:

date
shutdown 10:30 'pw-test: schedule at 10:30'
shutdown -c 'pw-test: cancel hh:mm'

实测回显:

$ date
Fri Oct 16 09:49:56 UTC 2026
$ shutdown 10:30 'pw-test: schedule at 10:30'
Shutdown scheduled for Fri 2026-10-16 10:30:00 UTC, use 'shutdown -c' to cancel.
$ shutdown -c 'pw-test: cancel hh:mm'

💡 要点:hh:mm 的确认消息里目标时刻精确到秒且秒位固定为 00(10:30:00)。生产上「凌晨低峰重启」场景就是用这个格式:shutdown -r 02:00。注意时区——计划按系统本地时区解释(本机为 UTC),跨时区团队写运维脚本时要先 date 确认再写死时刻。

3.4 -c:取消已登记的计划(含重复计划与空取消)

-c 取消当前计划,可带一条广播消息通知所有用户「关机已取消」。三种边界行为实测——正常取消、重复计划覆盖、无计划时取消:

shutdown +5 'pw-test: first schedule'
shutdown +5 'pw-test: second schedule'
shutdown -c 'pw-test: cancel the schedule'
busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
shutdown -c
echo "空取消退出码=$?"

实测回显:

$ shutdown +5 'pw-test: first schedule'
Shutdown scheduled for Fri 2026-10-16 09:53:45 UTC, use 'shutdown -c' to cancel.
$ shutdown +5 'pw-test: second schedule'
Shutdown scheduled for Fri 2026-10-16 09:53:45 UTC, use 'shutdown -c' to cancel.
$ shutdown -c 'pw-test: cancel the schedule'
$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
(st) "" 0
$ shutdown -c
$ echo "空取消退出码=$?"
空取消退出码=0

💡 要点:

  1. 重复执行 shutdown(同一次会话里连发两次 +5)不会报错,第二次直接覆盖第一次的计划,两次都返回确认消息——这对脚本幂等友好,但也意味着并行运维时后发的人会悄悄改掉先发的人的计划,重要变更应通过工单协调。
  2. 取消后 ScheduledShutdown 属性回到 (st) "" 0(空动作 + 时间戳 0),与 3.2 节的计划态形成对照。
  3. 没有计划时执行 -c 也是退出码 0、无任何输出——-c 是幂等的,Ansible 批量收尾时可以放心追加。

3.5 --show:systemd 249 不支持(真实踩坑)与 busctl 替代方案

不少教程提到 shutdown --show 可查看当前计划,但在 systemd 249(Ubuntu 22.04)上实测该选项不存在:

shutdown --show
echo "退出码=$?"

实测回显:

$ shutdown --show
shutdown: unrecognized option '--show'
$ echo "退出码=$?"
退出码=1

替代方案就是 3.2/3.4 节用过的 busctl 属性查询,计划态与空闲态的返回值如下:

busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown

实测回显(有计划时):

(st) "poweroff" 1792144496349858

实测回显(无计划时):

(st) "" 0

💡 要点:unrecognized option 退出码为 1。把 shutdown --show 写进监控脚本会静默失败,Ubuntu 22.04 上应统一用 busctl(或用 systemctl list-jobs 观察是否有 shutdown 相关 job,但计划态的权威来源是 logind 属性)。

3.6 -k:假广播(只发警告,不真停机)

-k(kick 的含义)执行一次完整的「计划 + 广播」流程,但不会真的停机——它告诉所有登录用户「系统将要停机」,用于停机前的预演或预警演练:

shutdown -k now 'pw-test: fake shutdown for demo'
echo "退出码=$?"
shutdown -k +5 'pw-test: kiosk warning only'
echo "退出码=$?"
shutdown -c

实测回显:

$ shutdown -k now 'pw-test: fake shutdown for demo'
$ echo "退出码=$?"
退出码=0
$ shutdown -k +5 'pw-test: kiosk warning only'
Shutdown scheduled for Fri 2026-10-16 09:54:56 UTC, use 'shutdown -c' to cancel.
$ echo "退出码=$?"
退出码=0
$ shutdown -c

💡 要点:

  1. -k now 无输出、退出码 0,主机继续正常运行;-k +5 依然返回「Shutdown scheduled」确认消息——logind 真的登记了计划(这也是为什么结尾要 -c 收尾),只是到点不执行停机动作。
  2. 广播消息的送达对象是 utmp 登记的登录会话(SSH、本地 tty 等)。本次实测的运维会话未走登录流程登记,终端上看不到 Broadcast 字样;正常 SSH 会话会收到形如 Broadcast message from root@主机名 (pts/0) ... 的多行警告。广播不可见不影响 -k 生效,可用 3.9 节的 journal 证据验证。
  3. -k 是停机演练的安全姿势:先 -k +30 '系统将于 30 分钟后重启' 预告,到点前再发真计划,给值班人员留反应时间。

3.7 TIME 非法值:报错与退出码

脚本里对 TIME 参数做校验前,先看三类非法输入的真实报错:

shutdown -1; echo "负数退出码=$?"
shutdown abc; echo "乱串退出码=$?"
shutdown 99:99; echo "越界时刻退出码=$?"

实测回显:

$ shutdown -1; echo "负数退出码=$?"
shutdown: invalid option -- '1'
负数退出码=1
$ shutdown abc; echo "乱串退出码=$?"
Failed to parse time specification: abc
乱串退出码=1
$ shutdown 99:99; echo "越界时刻退出码=$?"
Failed to parse time specification: 99:99
越界时刻退出码=1

💡 要点:

  1. abc、99:99 统一报 Failed to parse time specification: <原值>,退出码 1;变量拼接出空串或乱串时命令会失败而不是意外关机,这是脚本安全的好消息。
  2. -1 被当成短选项解析(shutdown: invalid option -- '1'),说明以 - 开头的字符串会先被选项解析器拦截——TIME 槽位不接收负数。
  3. 三类非法输入都只会报错退出,不会触发任何停机动作;脚本里应检查退出码是否为 0 来确认计划是否真的登记成功。

3.8 非 root 执行:Access denied

普通用户执行 shutdown 会被 logind 拒绝。先创建演示用户,再用 su 切换实测:

useradd -m -s /bin/bash pwuser
su - pwuser -c "shutdown +5 'pw-test: by non-root'"
echo "非root退出码=$?"
su - pwuser -c "shutdown -c"
echo "非root取消退出码=$?"

实测回显:

$ useradd -m -s /bin/bash pwuser
$ su - pwuser -c "shutdown +5 'pw-test: by non-root'"
Failed to set wall message, ignoring: Access denied
Failed to call ScheduleShutdown in logind, no action will be taken: Access denied
非root退出码=1
$ su - pwuser -c "shutdown -c"
非root取消退出码=0

清理演示用户(su 的会话进程会短暂占用账号,删除时可能提示进程占用):

$ userdel -r pwuser
userdel: user pwuser is currently used by process 139

💡 要点:

  1. 非 root 有两行报错:第一行 Failed to set wall message(广播消息设置被拒,但被忽略不影响流程),第二行 Failed to call ScheduleShutdown in logind(计划登记被拒,明确说 no action will be taken),整体退出码 1。普通用户不可能通过 shutdown 停机。
  2. 有趣的是非 root 的 shutdown -c 返回了退出码 0——logind 对取消接口的拒绝没有体现在退出码上,不要依赖「-c 成功」来判断用户有计划管理权限。
  3. userdel 报 currently used by process 是因为 su 的会话进程还挂着;运维清理演示账号时应先结束其会话再删除,或等待片刻后重试。

3.9 wall 广播与 /run/nologin 的生效机制

shutdown 的两个副作用常被误解,本节用 journal 实测厘清。广播(wall message)只投递给 utmp 登记的登录会话;/run/nologin 则在计划确立时由 systemd-logind 创建。查看 logind 的 journal 记录:

journalctl -u systemd-logind --no-pager -n 30 | tail -15

实测回显(节选关键段):

Oct 15 18:07:39 b8307d66e0c6 systemd[1]: Starting User Login Management...
Oct 15 18:07:39 b8307d66e0c6 systemd-logind[45]: New seat seat0.
Oct 15 18:07:39 b8307d66e0c6 systemd[1]: Started User Login Management.
Oct 16 09:48:45 b8307d66e0c6 systemd-logind[45]: Creating /run/nologin, blocking further logins...
Oct 16 09:48:45 b8307d66e0c6 systemd-logind[45]: Creating /run/nologin, blocking further logins...
Oct 16 09:48:45 b8307d66e0c6 systemd-logind[45]: Creating /run/nologin, blocking further logins...
Oct 16 09:49:56 b8307d66e0c6 systemd-logind[45]: Creating /run/nologin, blocking further logins...
Oct 16 09:49:56 b8307d66e0c6 systemd-logind[45]: Creating /run/nologin, blocking further logins...

💡 要点:

  1. 每一条 Creating /run/nologin, blocking further logins... 对应一次「距停机不足 5 分钟」的计划登记(09:48:45 的三次对应 +5、-k 系列与重复计划,09:49:56 的两次对应 hh:mm 后紧跟的 +5 与 -k +5)。hh:mm 这类距执行还有 40 分钟的计划不会立即创建 /run/nologin——logind 把创建动作安排在停机前 5 分钟触发(对 +5 而言就是立刻)。
  2. /run/nologin 文件内容(3.2 节实测)是固定文案 System is going down. Unprivileged users are not permitted to log in anymore. ...,PAM 的 pam_nologin(8) 模块读取它拦截非 root 登录;shutdown -c 取消计划时会一并删除该文件(3.2 节实测取消后 ls 报 No such file or directory)。
  3. 广播消息经 D-Bus 由 logind 派发,只写 utmp 登记的终端;对未登记的自动化会话(本文实测场景)不可见,但计划本身照常生效。排查「用户说没收到通知」时,先确认对方的会话类型与登录时间点,再看本节 journal 是否有对应计划记录。

3.10 now:立即关机(默认动作)

不带任何选项的 shutdown now 是最常用的立即关机形态,默认动作为关机断电(等同 -P)。命令提交后没有任何输出,主机随即进入优雅停机流程,会话断开;重新开机后用 wtmp 留痕验证:

shutdown now 'pw-test: default poweroff with wall msg'

实测回显:命令本身无输出,主机停止运行。主机重新启动后查看停机留痕:

$ last -x | head -5
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 09:54   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 09:54   still running
shutdown system down  6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)
reboot   system boot  6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)

💡 要点:

  1. shutdown system down 记录就是这次关机的留痕:system down 表示系统停止,括号里的 (00:00) 是本次运行时长(本机停机后立即重启,时长不足 1 分钟)。其上的 reboot system boot ... still running 是重启后的新开机记录。
  2. last -x 输出中的内核字段 6.8.0-138-generi 是 wtmp 记录里内核版本 6.8.0-138-generic 的截断显示(字段宽度限制),属正常现象。
  3. wtmp 停机记录由 systemd 关机流程中的 systemd-update-utmp(对应 journal 里 Record System Boot/Shutdown in UTMP 单元的停止)写入,因此 3.14 节的强制停机路径不会产生该记录——这一点是审计时区分「优雅关机」与「强制/异常停机」的依据。

3.11 -h:等同关机断电(可被 --halt 覆盖的历史参数)

-h 是 SysV 时代流传下来的参数,在 systemd 上默认等价于 -P(关机断电);2.2 节帮助原文标注它可被 --halt 覆盖(-H -h 组合时 -h 让位)。实测单独使用:

shutdown -h now

实测回显:命令无输出,主机停止。重启后 wtmp 留痕:

$ last -x | head -3
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 09:54   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 09:54   still running
shutdown system down  6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)

💡 要点:-h now 与 shutdown now 的 wtmp 留痕完全一致(shutdown system down),确认 -h 默认走关机断电而非挂起。老脚本里常见的 shutdown -h now 可以放心继续用,但新写脚本建议直接用 shutdown now 或 shutdown -P now,语义更明确。

3.12 -P:显式关机断电

-P(--poweroff)显式声明关机断电动作,是默认动作的长写法。实测:

shutdown -P now

实测回显:命令无输出,主机停止。重启后 wtmp 留痕:

$ last -x | head -3
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 09:54   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 09:54   still running
shutdown system down  6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)

💡 要点:-P 与 -h、无选项三者的结果完全一致(对比 3.10/3.11 的 wtmp 记录)。它的价值在于「自文档化」:运维手册、巡检脚本里写 shutdown -P now,读者不需要回忆默认值就知道动作是断电关机。

3.13 -H:halt 挂起(停机不断电)

-H(--halt)执行 halt 动作:停止系统服务与 CPU,但不发送断电信号。实测:

shutdown -H now

实测回显:命令无输出,主机停止。重启后 wtmp 留痕:

$ last -x | head -3
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 09:54   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 09:54   still running
shutdown system down  6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)

💡 要点:

  1. wtmp 记录与关机断电形态一致,无法从日志区分 halt 与 poweroff——两者的差别只发生在最后一步的电源控制(halt 不断电、poweroff 断电),wtmp 只记录到「系统停止」这一层。
  2. 在物理机上,halt 后机器停在黑屏通电状态,需要人工断电重启;在云主机/虚拟化平台上,halt 通常表现为实例直接停止,与关机难以区分。正因如此,生产环境几乎不用 -H,需要「重启」用 -r,需要「关机」用 -P 或默认。

3.14 --no-wall:停机但不广播

--no-wall 抑制停机前的广播消息,其余行为(计划、停机动作)不变。适合单管理员环境避免无意义的广播,或自动化流水线里不惊动在线用户:

shutdown --no-wall now

实测回显:命令无输出,主机停止。重启后 wtmp 留痕:

$ last -x | head -3
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 09:54   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 09:54   still running
shutdown system down  6.8.0-138-generi Fri Oct 16 09:54 - 09:54  (00:00)

💡 要点:wtmp 留痕与带广播的关机完全相同——--no-wall 只去掉广播这一步,不影响停机流程与日志。多人共用的服务器不建议使用该参数:无声无息的停机是团队协作事故的高发源头。

3.15 优雅停机日志实录:主机停止前系统做了什么

shutdown 触发的是 systemd 的优雅停机流程。以一次真实执行后的 journal 为证(本节引用实测环境中一次 shutdown -r now 之后保留的停机日志,全部发生在 09:57:29 一秒之内,先按时间窗口过滤再剔除内核行):

journalctl --no-pager --since '2026-10-16 09:57:24' --until '2026-10-16 09:57:30' | grep -v ' kernel: ' | head -60

实测回显:

Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Removed slice Slice /system/modprobe.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Graphical Interface.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Multi-User System.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Login Prompts.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Host and Network Name Lookups.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Timer Units.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: apt-daily-upgrade.timer: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Daily apt upgrade and clean activities.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: apt-daily.timer: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Daily apt download activities.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: dpkg-db-backup.timer: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Daily dpkg database backup timer.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: e2scrub_all.timer: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Periodic ext4 Online Metadata Check for All Filesystems.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: motd-news.timer: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Message of the Day.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-tmpfiles-clean.timer: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Daily Cleanup of Temporary Directories.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping Getty on tty1...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping Dispatcher daemon for systemd-networkd...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping User Login Management...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping Network Name Resolution...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: networkd-dispatcher.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Dispatcher daemon for systemd-networkd.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: getty@tty1.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Getty on tty1.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Removed slice Slice /system/getty.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping Permit User Sessions...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-resolved.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Network Name Resolution.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-logind.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped User Login Management.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-user-sessions.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Permit User Sessions.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Basic System.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Path Units.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Remote File Systems.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Slice Units.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Removed slice User and Session Slice.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Socket Units.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target System Initialization.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Local Encrypted Volumes.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-ask-password-console.path: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Dispatch Password Requests to Console Directory Watch.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-ask-password-wall.path: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Forward Password Requests to Wall Directory Watch.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Swaps.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped target Local Verity Protected Volumes.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping Set Up Additional Binary Formats...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-sysctl.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Apply Kernel Variables.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopping Record System Boot/Shutdown in UTMP...
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-binfmt.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Set Up Additional Binary Formats.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: proc-sys-fs-binfmt_misc.automount: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Unset automount Arbitrary Executable File Formats File System Automount Point.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: proc-sys-fs-binfmt_misc.mount: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-update-utmp.service: Deactivated successfully.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: Stopped Record System Boot/Shutdown in UTMP.
Oct 16 09:57:29 b8307d66e0c6 systemd[1]: systemd-tmpfiles-setup.service: Deactivated successfully.

💡 要点:

  1. 停机顺序:先停各目标(Timers → Multi-User → Login Prompts),再停具体服务(getty、logind、resolved 等),然后进入 System Shutdown → Late Shutdown Services(见 3.10 节同一窗口内更靠后的行 Reached target Unmount All Filesystems/Reached target System Shutdown/Reached target Late Shutdown Services,重启动作则以 Reached target System Reboot 收尾)。
  2. 倒数第几行的 Stopping Record System Boot/Shutdown in UTMP... 正是 3.10 节 wtmp 停机留痕的写入者(systemd-update-utmp 单元)——它作为停机流程的收尾服务被停止,wtmp 的 down 记录由它负责落盘。
  3. 这段日志是排查「关机卡住」的第一现场:卡在哪一步,journal 的最后几行会停在对应的 Stopping ... 上,通常是某个服务未响应 SIGTERM,等待超时(默认 90 秒)后被强杀。
  4. 实测轻负载系统从第一个 Stopping 到最终 target 到达在一秒内完成,说明停机瓶颈通常不在 systemd 流程本身。

3.16 拓展:shutdown 与 reboot/halt/poweroff/systemctl/init 0 对比

Ubuntu 22.04 上所有停机入口最终都汇入 systemd 同一套流程,但入口的「性格」不同。基于本文与配套篇目的实测结论汇总:

入口计划/延时广播警告取消优雅停机流程典型用途
shutdown支持(now/+m/hh:mm)支持(WALL 参数)-c走 logind 计划 + systemd 全流程生产停机/重启的标准姿势
reboot不支持(立即)有默认广播(--no-wall 可关)无走 systemd 全流程快速重启
halt不支持有(--no-wall 可关)无走 systemd 全流程(systemd 上等效关机)极少用
poweroff不支持有(--no-wall 可关)无走 systemd 全流程快速关机
systemctl poweroff / reboot不支持无 wall 广播无走 systemd 全流程脚本内调用
init 0 / init 6不支持无无兼容入口,转译为 systemd 动作SysV 兼容脚本

强制模式的差异另见配套篇目:reboot -f/halt -f/poweroff -f 跳过优雅流程直接发起内核级动作(实测回显 Rebooting./Halting./Powering off.,wtmp 中不产生 shutdown system down 记录)。

💡 要点:选型口诀——要计划、要广播、要可取消,用 shutdown;要快,用 reboot/poweroff;要写脚本,优先 systemctl 或 shutdown now。init 0/init 6 只在维护祖传脚本时保留。

四、实战示例

4.1 场景一:凌晨低峰定时重启(计划 + 确认 + 兜底取消)

维护窗口重启是最经典的生产场景:提前安排凌晨 02:00 重启,登记后用 busctl 确认计划存在,若当天变更临时取消则用 -c 收尾。实测本机时间 10:15 发起,02:00 已过,shutdown 自动把计划安排到次日 02:00。以下为完整可执行的安全闭环(最后取消,主机不真重启):

date
shutdown -r 02:00 'pw-test: kernel maintenance reboot at 02:00'
echo "退出码=$?"
busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
shutdown -c 'pw-test: maintenance postponed'
busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown

实测回显:

$ date
Fri Oct 16 10:15:31 UTC 2026
$ shutdown -r 02:00 'pw-test: kernel maintenance reboot at 02:00'
Reboot scheduled for Sat 2026-10-17 02:00:00 UTC, use 'shutdown -c' to cancel.
$ echo "退出码=$?"
退出码=0
$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
(st) "reboot" 1792202400000000
$ shutdown -c 'pw-test: maintenance postponed'
$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown
(st) "" 0

验证闭环:计划登记 → 属性为 reboot + 次日 02:00 的时间戳 → 取消 → 属性归零。两个值得记住的细节:

  1. -r 动作的确认消息前缀是 Reboot scheduled(3.2 节默认关机动作则是 Shutdown scheduled),从消息前缀即可分辨动作类型;
  2. hh:mm 已过时自动顺延次日(实测 10:15 发起 02:00 计划,安排到周六 02:00),写跨夜维护脚本时无需自行处理日期换算。

4.2 场景二:变更执行完毕立即重启并确认生效

内核小版本升级、安全补丁等变更后需要立即重启,并在系统回来后确认「确实重启过一次」:

shutdown -r now

实测回显:命令无输出,主机重启。系统恢复后验证:

$ who -b
         system boot  Oct 16 10:08
$ last -x reboot | head -3
reboot   system boot  6.8.0-138-generi Fri Oct 16 10:08   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 10:08   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)

要点:who -b 给出本次开机时刻,last -x reboot 可回溯每一次重启;变更单里贴这两条输出即可证明重启完成。

4.3 场景三:停机前的预警广播演练(-k)

大范围停机前先做一轮「假广播」,验证广播链路与值班响应,确认无误后再发真计划:

shutdown -k +30 'pw-test: DRILL - real shutdown at +60min, please save work'
echo "演练广播退出码=$?"
shutdown -c

实测回显:

$ shutdown -k +30 'pw-test: DRILL - real shutdown at +60min, please save work'
Shutdown scheduled for Fri 2026-10-16 10:45:31 UTC, use 'shutdown -c' to cancel.
$ echo "演练广播退出码=$?"
演练广播退出码=0
$ shutdown -c

要点:-k +30 会真实登记计划(确认消息照发,发起时刻 10:15:31 + 30 分钟 = 10:45:31),因此演练后必须 -c 取消,否则 logind 里会挂着一个到点不停机的空计划;SSH 登录用户会在终端看到 Broadcast 警告(广播投递依赖 utmp 登记会话,见 3.9 节机制说明)。

4.4 场景四:异常停机审计(区分优雅关机与强制停机)

安全审计、故障复盘时需要回答「这台机器上次是不是被强制断电的」。判据:优雅关机(shutdown/poweroff)在 wtmp 里留 shutdown system down 记录;强制模式(reboot -f 等)跳过该流程,不留 down 记录。查看本文实测留下的完整对账:

$ last -x shutdown | head -8
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:08  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:07 - 10:07  (00:00)
shutdown system down  6.8.0-138-generi Fri Oct 16 10:04 - 10:04  (00:00)

对照的强制停机实测(poweroff -f 执行后,重启立即查看,没有新增 shutdown 记录):

$ last -x | head -4
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 10:08   still running
reboot   system boot  6.8.0-138-generi Fri Oct 16 10:08   still running
runlevel (to lvl 5)   6.8.0-138-generi Fri Oct 16 10:08 - 10:08  (00:00)
reboot   system boot  6.8.0-138-generi Fri Oct 16 10:08   still running

要点:逐段核对 reboot system boot 与 shutdown system down 的配对关系,出现「有 boot 无 down」即该次停机未走优雅流程(强制模式或断电/崩溃),再结合 journal 的停机时刻日志进一步定性。

五、注意事项与常见问题

Q1:shutdown now 和直接执行 reboot / poweroff 有什么区别? 核心差异是「计划 + 广播 + 可取消」。shutdown 支持 +m/hh:mm 延时、支持自定义广播消息、支持 -c 取消;reboot/poweroff 是立即执行、无法取消的短平快入口。四者在 systemd 上走同一套优雅停机流程(3.16 节对比表),日常运维优先 shutdown。

Q2:shutdown --show 报 unrecognized option 是坏了吗? 不是。systemd 249(Ubuntu 22.04)的 shutdown 没有 --show 选项(3.5 节实测 unrecognized option 退出码 1),更高版本的 systemd 才引入。Ubuntu 22.04 上查计划用 busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ScheduledShutdown,有计划返回 (st) "poweroff" <时间戳>,无计划返回 (st) "" 0。

Q3:shutdown -c 执行后没有任何输出,取消成功了吗? 成功了。-c 幂等:有计划则取消(3.4 节),无计划也返回退出码 0。要拿到确定性的确认,用 Q2 的 busctl 查询计划属性,归零即取消完成。

Q4:计划登记后普通用户为什么登不上了? shutdown 的计划距执行不足 5 分钟时,systemd-logind 会创建 /run/nologin(3.2/3.9 节实测文件内容与 journal 记录),PAM 的 pam_nologin 模块据此拒绝非 root 新登录,root 不受影响。取消计划(-c)后该文件被自动删除,登录恢复。

Q5:普通用户执行 shutdown 报 Access denied,怎么授权? 默认无解:非 root 调用 logind 的 ScheduleShutdown 被直接拒绝(3.8 节实测两行报错 + 退出码 1)。需要让特定运维人员能关机,应通过 sudo 精确放行 shutdown 命令(visudo 配置命令白名单),而不是修改 logind 策略。

Q6:-k 到底会不会误关机? 不会。-k 只走「计划 + 广播」流程,到点不执行停机动作(3.6 节实测主机持续运行)。但注意它会真实登记计划并可能创建 /run/nologin(距执行 5 分钟内时),演练后务必 shutdown -c 清理。

Q7:wall 广播在正常 SSH 会话里长什么样?为什么我的会话没收到? 广播由 logind 投递给 utmp 里登记的登录会话,SSH/本地 tty 登录会收到形如「Broadcast message from root@主机名 (...)」的多行警告。未走登录流程的会话(自动化连接、部分远程执行通道)不在投递名单里,收不到广播但计划照常生效(3.9 节)。排查送达问题先看会话是否在 who 输出中。

Q8:-h、-P、-H 三者到底怎么选? -h 是历史兼容参数,systemd 上默认等同 -P(3.11 节实测留痕一致);-P 显式断电关机,是语义最清晰的选择;-H 是挂起不断电(3.13 节),物理机上会停在通电黑屏状态,云平台上通常表现为实例停止。生产口诀:关机用 -P 或不写,重启用 -r,-H 基本不用。

Q9:同一时段两个运维各发了一个 shutdown 计划,最终听谁的? 后发的覆盖先发的(3.4 节实测两次 +5 均返回确认消息且计划被覆盖),没有任何警告。多人协作环境应在变更单里约定唯一计划发起人,或登记后立即用 Q2 的 busctl 查询核对动作类型与目标时间是否符合预期。

六、参考链接