who 命令详解与参数实测(Ubuntu 22.04)
who 命令逐参数实测详解:基于真实 SSH 登录会话采集 utmp 记录,覆盖默认输出、-s/-H/-u/-q/-T/-w/-b/-r/-t/-d/-l/-p/-a/-m/--ips/--lookup 与 FILE 读 wtmp 历史,含 mesg 状态联动、who am i 形态、定位 PID 踢会话下线与登录历史审计实战,全部回显在 Ubuntu 22.04 实测通过。
who 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 who 的每一个常用参数——默认输出、
-s短格式、-H标题行、-u用户详情(IDLE/PID)、-q计数、-T/-w消息状态、-b/-r/-t、-d死进程、-l/-p、-a全量、-m与who am i经典形态、--ips、--lookup,以及 FILE 参数读取 wtmp 历史与「踢登录会话下线」实战,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。
一、环境信息
本节记录实测环境与演示数据。who 是登录会话查询的入口命令:回答「现在有谁登录在这台机器上、从哪里、什么时候、在哪个终端」。它的数据来源是 utmp 登录数据库——没有真实登录会话就没有输出,因此本文先搭建真实的 SSH 登录会话再逐参数实测,回显均为登录记录存在时的真实形态。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- who 版本:GNU coreutils 8.32(软件包 coreutils 8.32-4.1ubuntu1.4,见 2.3 实测)
- SSH 服务:openssh-server(sshd 监听 22 端口,用于产生真实登录会话)
- Shell:GNU bash 5.1.16
- 演示目录:
/root/demo/who/ - 测试用户:
u4a-ssh(普通用户,密码 q1w2e3r4),通过 SSH 从本机登录建立多个常驻会话(pts/5、pts/6 等) - 登录记账文件:
/run/utmp(当前会话)、/var/log/wtmp(历史登录)
二、命令概览
2.1 语法与测试数据(SSH 登录会话准备)
who 的语法为:
who [OPTION]... [ FILE | ARG1 ARG2 ]
三种用法:① 纯选项,读默认文件 /run/utmp 列出当前登录用户;② [FILE] 形式,读指定记账文件(惯例是 /var/log/wtmp 看历史);③ ARG1 ARG2 两参数形式(即 who am i),只显示与标准输入关联的登录会话。
关键前置:准备真实登录会话。 utmp 记录由登录服务(sshd、login 等)在**分配了伪终端(PTY)**的会话建立时写入。先安装 openssh-server 并创建测试用户:
apt-get install -y openssh-server
useradd -m -s /bin/bash u4a-ssh
echo 'u4a-ssh:q1w2e3r4' | chpasswd
mkdir -p /run/sshd && /usr/sbin/sshd
验证 sshd 就绪(监听 22 端口):
$ ss -tlnp | grep :22
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=6267,fd=3))
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=6267,fd=4))
然后用 ssh -tt 建立两个常驻登录会话(-tt 强制分配 PTY,这是 utmp 有记录的关键):
sshpass -p q1w2e3r4 ssh -tt u4a-ssh@localhost "sleep 1800" &
sshpass -p q1w2e3r4 ssh -tt u4a-ssh@localhost "tail -f /dev/null" &
确认 utmp 数据库已产生记录:
$ ls -l /run/utmp
-rw-rw-r-- 1 root utmp 1920 Oct 15 09:06 /run/utmp
$ getent group utmp
utmp:x:43:
/run/utmp 归 root 与 utmp 组可写(登录服务写它,普通命令读它),文件已存在且在会话建立时间点(09:06)更新过。
💡 技术拓展:Linux 的登录记账是一套「四文件家族」,who/w/last 等命令各读其一,排查登录问题时务必分清——
文件 记录内容 写入者 典型读取命令 /run/utmp当前登录会话快照(重启即清空) sshd/login 等建立会话时 who、w、users/var/log/wtmp历史登录/退出流水(追加式) 会话建立与退出时 last、who /var/log/wtmp/var/log/btmp失败登录尝试(爆破审计) 认证失败时 lastb/var/log/lastlog每用户最近一次成功登录 成功登录时 lastlog本文实测以
/run/utmp(当前会话)为主线,3.14 节实测/var/log/wtmp历史读取;who 只读不写,生产上注意 utmp 类文件损坏(如异常断电残留半条记录)会让 who 输出异常行。
2.2 --help 全量回显
who 的选项是本组命令中最多的。以下为 who --help 完整回显,逐行照抄:
$ who --help
Usage: who [OPTION]... [ FILE | ARG1 ARG2 ]
Print information about users who are currently logged in.
-a, --all same as -b -d --login -p -r -t -T -u
-b, --boot time of last system boot
-d, --dead print dead processes
-H, --heading print line of column headings
--ips print ips instead of hostnames. with --lookup,
canonicalizes based on stored IP, if available,
rather than stored hostname
-l, --login print system login processes
--lookup attempt to canonicalize hostnames via DNS
-m only hostname and user associated with stdin
-p, --process print active processes spawned by init
-q, --count all login names and number of users logged on
-r, --runlevel print current runlevel
-s, --short print only name, line, and time (default)
-t, --time print last system clock change
-T, -w, --mesg add user's message status as +, - or ?
-u, --users list users logged in
--message same as -T
--writable same as -T
--help display this help and exit
--version output version information and exit
If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common.
If ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/who>
or available locally via: info '(coreutils) who invocation'
💡 说明:三处划线——①
-a是same as -b -d --login -p -r -t -T -u的组合开关;② 帮助末尾明确「不指定 FILE 用 /var/run/utmp,/var/log/wtmp 是常见选择」;③ 「ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual」解释了who am i这类口语化用法的真实身份——两个位置参数触发-m模式,单词本身无魔法。
2.3 版本信息
who 同属 coreutils,版本号与 whoami/id 一致:
$ who --version
who (GNU coreutils) 8.32
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Joseph Arceneaux, David MacKenzie, and Michael Stone.
$ type who
who is hashed (/usr/bin/who)
is hashed (/usr/bin/who) 确认 who 是 coreutils 独立程序。日常取版本号一行即可:
$ who --version | head -1
who (GNU coreutils) 8.32
三、参数逐项实测
以下实测均基于 2.1 建立的两个常驻 SSH 登录会话(u4a-ssh,pts/5 跑 sleep 1800、pts/6 跑 tail -f /dev/null)。
3.1 无参数:列出当前登录用户
不带选项的 who 逐行输出每个登录会话的「用户名、终端、登录时间、来源」:
$ who
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
确认退出码为 0:
$ who; echo "exit=$?"
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
exit=0
四列语义:u4a-ssh 是登录名;pts/5 是伪终端设备名(对应 /dev/pts/5);Oct 15 09:06 是会话建立时间;括号里的 (::1) 是登录来源主机(本机回环 IPv6 地址,即从 localhost SSH 登录)。
-s(--short)在帮助里标注为 (default)——输出与默认完全一致:
$ who -s
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
💡 要点:who 一行 = 一个登录会话。两个 SSH 窗口就是两行;同一用户开十个标签页就是十行。
pts/N是动态分配的伪终端,tty1~tty6则是本地虚拟控制台。
3.2 -H 标题行
-H(--heading)在输出顶部加一行列标题,便于阅读与讲解:
$ who -H
NAME LINE TIME COMMENT
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
与 -u 联用时标题列同步变化(多了 IDLE 与 PID):
$ who -H -u
NAME LINE TIME IDLE PID COMMENT
u4a-ssh pts/5 Oct 15 09:06 . 16571 (::1)
u4a-ssh pts/6 Oct 15 09:06 . 16572 (::1)
💡 要点:
-H只加标题不改数据列,适合人读;脚本解析 who 输出时不要加-H,省得跳过标题行。
3.3 -u 用户详情:IDLE 与 PID
-u(--users)扩展输出,增加「空闲时长 IDLE」与「会话进程 PID」两列:
$ who -u
u4a-ssh pts/5 Oct 15 09:06 . 16571 (::1)
u4a-ssh pts/6 Oct 15 09:06 . 16572 (::1)
IDLE 列的取值规则实测验证:会话刚有活动时显示 .(一分钟内),空闲后显示 HH:MM。约 2 分钟后同一条命令的输出变为:
$ date
Thu Oct 15 09:08:37 UTC 2026
$ who -u
u4a-ssh pts/5 Oct 15 09:06 00:02 16571 (::1)
u4a-ssh pts/6 Oct 15 09:06 00:02 16572 (::1)
再过一分钟增长为 00:03、00:04(见 4.2 实测),证实 IDLE 随时间单调增长。
💡 要点:
who -u是「找僵尸会话」的标准工具——IDLE 巨大(如10:32)的行就是挂着没动的终端;PID 列给出可操作的进程号,配合 kill 可以踢会话下线(4.2 实战)。IDLE 计的是终端输入活动,跑着长命令但没敲键的会话同样会被计入空闲。
3.4 -q 登录计数
-q(--count)只输出登录用户名列表与总数两行:
$ who -q
u4a-ssh u4a-ssh
# users=2
💡 要点:
# users=2是写日志/巡检报告最常用的形态;用户名按会话重复出现(同一用户两个会话就出现两次),所以总人数要按会话数理解。
3.5 -T / -w 消息状态:mesg 联动实测
-T、-w、--mesg 三写法等价:在用户名后插入一列消息状态符,表示该终端是否接受 write/talk 消息:
$ who -T -H
NAME LINE TIME COMMENT
u4a-ssh + pts/5 Oct 15 09:06 (::1)
u4a-ssh + pts/6 Oct 15 09:06 (::1)
$ who -w -H
NAME LINE TIME COMMENT
u4a-ssh + pts/5 Oct 15 09:06 (::1)
u4a-ssh + pts/6 Oct 15 09:06 (::1)
状态符含义:+ 可写(mesg y)、- 不可写(mesg n)、? 异常(无法定位终端)。在 SSH 会话内用 mesg n 切换后实测状态符即时变化:
$ mesg n; who -T | grep u4a; mesg y; who -T | grep u4a
u4a-ssh + pts/5 Oct 15 09:06 (::1)
u4a-ssh + pts/6 Oct 15 09:06 (::1)
u4a-ssh - pts/8 Oct 15 09:09 (::1)
u4a-ssh + pts/5 Oct 15 09:06 (::1)
u4a-ssh + pts/6 Oct 15 09:06 (::1)
u4a-ssh + pts/8 Oct 15 09:09 (::1)
mesg n 后 pts/8 的状态符立即从 + 变 -,mesg y 恢复为 +。
💡 要点:
-T是管理员广播消息前的安全检查——只给+的会话发 write 才有意义。mesg 改的是终端设备权限位(/dev/pts/N 的组写权限),who -T 只是把这个权限位可视化。
3.6 -b / -r / -t:启动时间、运行级别、时钟变更(空输出的真相)
三个参数在由 init/systemd 管理启动的系统上分别读取 utmp 里的 BOOT、RUNLEVEL、OLDTIME 记录:
$ who -b
$ who -r
$ who -t
本环境的输出全部为空——这是机制性结果而非故障:这三类记录由系统初始化进程(init/systemd)在开机、切换运行级别、校准时钟时写入 utmp;本实测环境的 SSH 服务以独立服务方式启动,不存在写这些记录的初始化进程,utmp 里自然没有对应条目。在正常的 systemd 服务器上,who -b 会输出形如 system boot 2026-10-15 08:30 的行,who -r 会输出 run-level 3 2026-10-15 08:30。
💡 要点:
who -b空 ≠ 系统没重启过,而是 utmp 里没有 BOOT 记录;查「上次开机时间」更稳的命令是uptime -s或last reboot(读 wtmp)。
3.7 -d 死进程
-d(--dead)列出 utmp 里的 DEAD_PROCESS 记录——已退出的会话残留在数据库中的「尸体行」:
$ who -d
pts/4 Oct 15 09:04 9253 id=ts/4 term=0 exit=0
pts/7 Oct 15 08:57 8364 id=ts/7 term=0 exit=0
pts/8 Oct 15 08:57 8365 id=ts/8 term=0 exit=0
三行分别对应此前退出过的三个会话(pts/4、pts/7、pts/8),term=0 exit=0 表示会话进程正常终止。用户名列是空的(死进程无用户身份)。
💡 要点:少量 DEAD_PROCESS 行是正常现象(正常退出会写记录);如果
who(或w)里出现了早已不存在的陈旧会话行,通常是会话异常终止(kill -9、断电)没来得及写 DEAD 记录所致,用-d能把它们暴露出来。
3.8 -l 登录进程与 -p init 进程
-l(--login)列出系统登录进程(LOGIN_PROCESS 记录,如传统 getty 监听的 tty):
$ who -l
-p(--process)列出由 init 派生的活动进程(INIT_PROCESS 记录):
$ who -p
两者在本环境均为空,原因同 3.6:没有 init/getty 体系在写这些记录。在有本地控制台登录服务的机器上,who -l 会列出各 tty 的 login 进程行。
💡 要点:
-l/-p主要服务传统 sysvinit 环境;systemd 机器上这两类记录同样稀少,日常排障优先用-u与-d。
3.9 -a 全量输出
-a(--all)等价于 -b -d --login -p -r -t -T -u 一次全开,把 utmp 里所有类型的记录都倒出来:
$ who -a
pts/4 Oct 15 09:04 9253 id=ts/4 term=0 exit=0
u4a-ssh + pts/5 Oct 15 09:06 . 16571 (::1)
u4a-ssh + pts/6 Oct 15 09:06 . 16572 (::1)
pts/7 Oct 15 08:57 8364 id=ts/7 term=0 exit=0
pts/8 Oct 15 08:57 8365 id=ts/8 term=0 exit=0
$ who -a -H
NAME LINE TIME IDLE PID COMMENT EXIT
pts/4 Oct 15 09:04 9253 id=ts/4 term=0 exit=0
u4a-ssh + pts/5 Oct 15 09:06 00:02 16571 (::1)
u4a-ssh + pts/6 Oct 15 09:06 00:02 16572 (::1)
pts/7 Oct 15 09:07 16804 id=ts/7 term=0 exit=0
pts/8 Oct 15 09:08 16963 id=ts/8 term=0 exit=0
第一段输出里,活动会话行带 + 状态符与来源,死进程行带 id= term= exit= 尾缀;第二段加 -H 后标题行包含 EXIT 列。-a 是「把 utmp 原样人肉解读」的最快方式,排障时比逐个参数试更高效。
💡 要点:
-a输出是混合体(活会话 + 死记录),判断「现在谁在线」请只用who或who -u;-a的价值在审计 utmp 完整内容。
3.10 -m 与 who am i 经典形态
-m 的语义是「只显示与标准输入关联的那个会话」(即当前终端自己的登录行)。在本环境外部执行(标准输入不关联任何登录会话),输出为空且退出码 0:
$ who -m
$ who -m; echo "exit=$?"
exit=0
进入真实 SSH 会话内执行,则显示该会话自身:
$ who -m
u4a-ssh pts/8 Oct 15 09:08 (::1)
who am i 就是 -m 的口语化形式(两个位置参数触发 -m,见 2.2 帮助原文),实测:
$ who am i
u4a-ssh pts/7 Oct 15 09:07 (::1)
任何两个单词都有同样效果,惯用语 mom likes 也不例外:
$ who mom loves
u4a-ssh pts/7 Oct 15 09:07 (::1)
同一会话内对比 whoami(有效 UID 的用户名):
$ whoami
u4a-ssh
💡 要点:
who am i回答「我从哪个终端登录进来的」,whoami 回答「我现在的有效身份是什么」。在 sudo/su 切换后二者分道扬镳:who am i仍是原始登录者,whoami 是切换后的用户(whoami 详解见《whoami 命令详解与参数实测(Ubuntu 22.04)》篇)。
3.11 --ips 显示 IP
--ips 让来源列显示 IP 而不是主机名。本环境登录来源本就是 IP 形态(::1),实测输出为 0.0.0.0(utmp 中未存独立 IP 字段时的回退值):
$ who --ips
u4a-ssh pts/5 Oct 15 09:06 0.0.0.0
u4a-ssh pts/6 Oct 15 09:06 0.0.0.0
$ who --ips -H
NAME LINE TIME COMMENT
u4a-ssh pts/5 Oct 15 09:06 0.0.0.0
u4a-ssh pts/6 Oct 15 09:06 0.0.0.0
💡 要点:utmp 记录的是「来源主机名或地址」一个字段,
--ips在无独立 IP 数据时的表现依实现而定(本环境显示 0.0.0.0)。要可靠的来源 IP 直接看默认输出的括号列即可,本环境就是(::1)。
3.12 --lookup 主机名规范化
--lookup 尝试对 utmp 里存的主机名做 DNS 规范化。本环境无 DNS 解析需求,输出与默认一致:
$ who --lookup | head -3
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
💡 要点:在 utmp 存的是短主机名、且内网有反向 DNS 的环境里,
--lookup会把短名展开成 FQDN;解析不通时可能因等待 DNS 超时而拖慢输出——脚本里慎用。
3.13 FILE 参数:读取 wtmp 登录历史
who 的第一个位置参数若不是 am i 形态的两词组合,就是记账文件名。传 /var/log/wtmp 即「翻历史」——输出按时间累计的所有登录/退出流水(与 last 同源):
$ who /var/log/wtmp | tail -5
u4b2 pts/8 Oct 15 08:57 (::1)
u4b-01longuser pts/4 Oct 15 08:59 (::1)
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
u4a-ssh pts/7 Oct 15 09:07 (::1)
输出按时间从旧到新排列,末尾即最近的登录(tail 取最后 5 条;前两行是同一环境下其他测试用户的会话,可见 wtmp 是全机共享的历史账本)。
💡 要点:
who /var/log/wtmp与last读同一文件;区别是 who 按原始记录逐行打印,last 做了会话配对(显示时长)。审计登录历史优先 last,快速看尾部用 who。
四、实战示例
4.1 一行统计在线人数与会话明细
巡检脚本里最常用的两个形态——计数与明细:
$ who | wc -l
2
$ who -q
u4a-ssh u4a-ssh
# users=2
who | wc -l 数行数,who -q 直接给 # users= 结论行,二者可交叉验证。放进报告模板只需一行拼接:
$ echo "$(date "+%F %T") 在线会话数: $(who | wc -l)"
2026-10-15 09:15:15 在线会话数: 2
4.2 定位并踢掉挂死的登录会话
「某同事离职了还挂着会话」「测试账号连接数占满」——标准处理链路是 who -u 找 PID → kill。先看当前会话全景:
$ who -u
u4a-ssh pts/5 Oct 15 09:06 00:03 16571 (::1)
u4a-ssh pts/6 Oct 15 09:06 00:03 16572 (::1)
u4a-ssh pts/8 Oct 15 09:10 . 17055 (::1)
pts/8 是刚建立的会话(IDLE 为 .),IDLE 之后的 PID 列即 17055。PID 在 who -u 输出里按空白切分是第 7 个字段(USER、TTY、TIME 占 3 词、IDLE 之后就是 PID),用 awk 精确提取(以 pts/5 会话实测同样写法):
$ who -u | awk '$2=="pts/5"{print $7}'
16571
确认目标进程后踢下线:
$ ps -p 17055 -o pid,cmd 2>/dev/null || echo "17055 已退出"
PID CMD
17055 sshd: u4a-ssh [priv]
$ kill -9 17055; echo "kill exit=$?"
kill exit=0
两秒后复查,pts/8 的行已从 utmp 消失:
$ who -u
u4a-ssh pts/5 Oct 15 09:06 00:04 16571 (::1)
u4a-ssh pts/6 Oct 15 09:06 00:04 16572 (::1)
⚠️ 注意一个实测发现:kill 的是 sshd 的会话监护进程,utmp 记录随之清除、who 不再显示,但会话内用户自己起的进程可能成为孤儿进程残留(实测 pts/8 里的 sleep 300 在 kill 后仍存在):
$ ps aux | grep "[s]leep 300" || echo "sleep 300 进程已消失"
u4a-ssh 17066 0.0 0.0 2792 1564 pts/8 Ss+ 09:10 0:00 sleep 300
彻底清理请补一句 pkill -u u4a-ssh -f 'sleep 300'(或 pkill -KILL -u 用户名 全量清场)。
4.3 登录身份与当前身份联合自检
登录跳板机/切完身份后,把「我从哪来」和「我现在是谁」一起打出来自检:
$ who am i
u4a-ssh pts/7 Oct 15 09:07 (::1)
$ whoami
u4a-ssh
若 whoami 输出与预期不符(比如本该是应用账户却显示 root),说明有意外提权,立即停下排查——这两条命令是登机检查式的存在,很多企业基线脚本把它们放在初始化段落。
4.4 登录历史快速审计
不装任何工具,用 who 读 wtmp 就能出一份「最近谁登录过」的速查表:
$ who /var/log/wtmp | tail -5
u4b2 pts/8 Oct 15 08:57 (::1)
u4b-01longuser pts/4 Oct 15 08:59 (::1)
u4a-ssh pts/5 Oct 15 09:06 (::1)
u4a-ssh pts/6 Oct 15 09:06 (::1)
u4a-ssh pts/7 Oct 15 09:07 (::1)
配合 grep 只看特定账号:
$ who /var/log/wtmp | grep "^u4a-ssh" | tail -3
u4a-ssh pts/8 Oct 15 09:09 (::1)
u4a-ssh pts/8 Oct 15 09:09 (::1)
u4a-ssh pts/8 Oct 15 09:10 (::1)
需要「每次登录持续了多久」时改用 last(同一数据源的配对版);需要失败登录审计则用 lastb(读 /var/log/btmp,见 2.1 拓展表)。
五、注意事项与常见问题
Q1:who 执行后什么都不输出,是坏了吗?
大概率是「当前环境没有写 utmp 的登录会话」,属机制性空输出。utmp 记录只在分配 PTY 的登录会话建立时写入:本地 console 登录、ssh -t/-tt 交互会话都会写;而 ssh host cmd 远程命令模式(实测进程名带 @notty)、cron 任务、守护进程都不写。验证方法:用 ssh -tt user@host 登录一次再看 who。另外注意 who 读的是 /run/utmp,该文件被误删或权限错乱(需 root:utmp 664)同样导致空输出。
Q2:who -b、who -r、who -t 都是空,怎么查开机时间?
这三个参数读的是 BOOT/RUNLEVEL/OLDTIME 记录,由 init/systemd 在开机与状态切换时写入(本文 3.6 实测了无 init 写入时三者为空)。查开机时间的可靠替代:uptime -s(直接从 /proc 推算)或 last reboot | head -3(读 wtmp 历史)。
Q3:who am i、whoami、who mom likes 到底什么关系?
whoami(coreutils 独立命令)= 当前有效 UID 的用户名;who am i = who 命令的 -m 模式(两个位置参数即触发,单词任意,mom likes 是社区玩笑式惯用语),显示当前标准输入所属的登录会话行。二者在未切换身份时输出一致,sudo/su 之后 who am i 不变而 whoami 跟着变——判断「我是谁登进来的」用前者,「我现在以谁的身份跑」用后者。
Q4:who -T 里状态符是 ? 是什么意思?
? 表示无法确定该记录对应终端的消息状态——通常意味着 utmp 里的 tty 路径已失效(设备不存在)。+=可写(mesg y)、-=不可写(mesg n)。给用户广播消息前先过滤 who -T | grep '\s+\s',对 + 的会话发 write。
Q5:who 和 w 都显示登录会话,该用哪个?
快照用 who(一行一会话、字段少而稳),分析负载与活动用 w(带 IDLE/JCPU/PCPU/WHAT,还能按用户过滤)。脚本解析优先 who(-q 的 # users=N 或 | wc -l);人工巡检优先 w。二者读同一个 /run/utmp,会话数必然一致。
Q6:utmp/wtmp 里的时间是本地时间还是 UTC?
who 显示的是记账记录里的时间戳,格式化时按当前时区渲染。跨时区排查时先用 date 确认本机时区,或直接 TZ=UTC who 对比输出,避免「登录时间对不上」的乌龙。历史审计(wtmp)建议用 last -F 显示完整年份与秒级时间。
六、参考链接
- GNU Coreutils 官方手册(who 章节):https://www.gnu.org/software/coreutils/manual/html_node/who-invocation.html
- who(1) 手册页(man7.org):https://man7.org/linux/man-pages/man1/who.1.html
- GNU Coreutils 在线帮助:https://www.gnu.org/software/coreutils/
- utmp(5) 登录记账文件格式(utmp/wtmp/btmp/lastlog 家族):https://man7.org/linux/man-pages/man5/utmp.5.html
- mesg(1) 手册页(-T 状态符的权限来源):https://man7.org/linux/man-pages/man1/mesg.1.html
- write(1) 手册页(who -T 的应用场景):https://man7.org/linux/man-pages/man1/write.1.html
- w(1) 手册页(同源姊妹命令):https://man7.org/linux/man-pages/man1/w.1.html
- whoami(1) 手册页(-m 形态的对照命令):https://man7.org/linux/man-pages/man1/whoami.1.html