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 的完整对比。
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
💡 要点:
- 四个命令全部指向
/bin/systemctl,本质上是同一套代码的不同入口;因此 2.2 节shutdown --help显示的是 shutdown 专属的短帮助,而不是 systemctl 的长帮助——systemctl 按 argv[0] 识别了身份。 - 这也解释了为什么
systemctl --version的版本就是 shutdown 的版本(2.3 节),以及为什么 shutdown 的停机日志与 systemctl 停机完全一致(同一流程)。 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
💡 要点:
- 确认消息的格式固定为
Shutdown scheduled for <日期 时间>, use 'shutdown -c' to cancel.,其中时间由「当前时间 + 5 分钟」精确计算(两次实测分别得到 09:54:56 与 09:56:52)。 busctl查到的(st) "poweroff" 1792144496349858是二元组:动作类型poweroff+ 目标时刻的微秒级时间戳;计划被取消后该属性变为(st) "" 0(见 3.4 节),这是 systemd 249 上查看计划的可靠手段。/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
💡 要点:
- 重复执行 shutdown(同一次会话里连发两次
+5)不会报错,第二次直接覆盖第一次的计划,两次都返回确认消息——这对脚本幂等友好,但也意味着并行运维时后发的人会悄悄改掉先发的人的计划,重要变更应通过工单协调。 - 取消后
ScheduledShutdown属性回到(st) "" 0(空动作 + 时间戳 0),与 3.2 节的计划态形成对照。 - 没有计划时执行
-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
💡 要点:
-k now无输出、退出码 0,主机继续正常运行;-k +5依然返回「Shutdown scheduled」确认消息——logind 真的登记了计划(这也是为什么结尾要-c收尾),只是到点不执行停机动作。- 广播消息的送达对象是 utmp 登记的登录会话(SSH、本地 tty 等)。本次实测的运维会话未走登录流程登记,终端上看不到 Broadcast 字样;正常 SSH 会话会收到形如
Broadcast message from root@主机名 (pts/0) ...的多行警告。广播不可见不影响-k生效,可用 3.9 节的 journal 证据验证。 -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
💡 要点:
abc、99:99统一报Failed to parse time specification: <原值>,退出码 1;变量拼接出空串或乱串时命令会失败而不是意外关机,这是脚本安全的好消息。-1被当成短选项解析(shutdown: invalid option -- '1'),说明以-开头的字符串会先被选项解析器拦截——TIME 槽位不接收负数。- 三类非法输入都只会报错退出,不会触发任何停机动作;脚本里应检查退出码是否为 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
💡 要点:
- 非 root 有两行报错:第一行
Failed to set wall message(广播消息设置被拒,但被忽略不影响流程),第二行Failed to call ScheduleShutdown in logind(计划登记被拒,明确说 no action will be taken),整体退出码 1。普通用户不可能通过 shutdown 停机。 - 有趣的是非 root 的
shutdown -c返回了退出码 0——logind 对取消接口的拒绝没有体现在退出码上,不要依赖「-c 成功」来判断用户有计划管理权限。 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...
💡 要点:
- 每一条
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而言就是立刻)。 /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)。- 广播消息经 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)
💡 要点:
shutdown system down记录就是这次关机的留痕:system down表示系统停止,括号里的(00:00)是本次运行时长(本机停机后立即重启,时长不足 1 分钟)。其上的reboot system boot ... still running是重启后的新开机记录。last -x输出中的内核字段6.8.0-138-generi是 wtmp 记录里内核版本6.8.0-138-generic的截断显示(字段宽度限制),属正常现象。- 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)
💡 要点:
- wtmp 记录与关机断电形态一致,无法从日志区分 halt 与 poweroff——两者的差别只发生在最后一步的电源控制(halt 不断电、poweroff 断电),wtmp 只记录到「系统停止」这一层。
- 在物理机上,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.
💡 要点:
- 停机顺序:先停各目标(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收尾)。 - 倒数第几行的
Stopping Record System Boot/Shutdown in UTMP...正是 3.10 节 wtmp 停机留痕的写入者(systemd-update-utmp 单元)——它作为停机流程的收尾服务被停止,wtmp 的 down 记录由它负责落盘。 - 这段日志是排查「关机卡住」的第一现场:卡在哪一步,journal 的最后几行会停在对应的
Stopping ...上,通常是某个服务未响应 SIGTERM,等待超时(默认 90 秒)后被强杀。 - 实测轻负载系统从第一个 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 的时间戳 → 取消 → 属性归零。两个值得记住的细节:
-r动作的确认消息前缀是Reboot scheduled(3.2 节默认关机动作则是Shutdown scheduled),从消息前缀即可分辨动作类型;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 查询核对动作类型与目标时间是否符合预期。
六、参考链接
- shutdown(8) 手册(Ubuntu 22.04 jammy):https://manpages.ubuntu.com/manpages/jammy/en/man8/shutdown.8.html
- systemd-logind.service(8) 与 logind 计划停机机制:https://manpages.ubuntu.com/manpages/jammy/en/man8/systemd-logind.service.8.html
- pam_nologin(8)(/run/nologin 拦截登录的 PAM 模块):https://manpages.ubuntu.com/manpages/jammy/en/man8/pam_nologin.8.html
- busctl(1)(D-Bus 属性查询,本实机查看计划的手段):https://manpages.ubuntu.com/manpages/jammy/en/man1/busctl.1.html
- last(1) / wtmp 停机留痕:https://manpages.ubuntu.com/manpages/jammy/en/man1/last.1.html
- systemd 官方源码仓库:https://github.com/systemd/systemd