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 实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行用户权限2026/10/15

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 显示完整年份与秒级时间。

六、参考链接