Linux who命令详解

who 命令用于显示当前登录系统的用户信息。它可以显示登录用户名、终端设备、登录时间、来源IP地址等,是系统管理员监控用户登录情况的重要工具。

1. 命令语法

who [选项] [文件]

2. 常用选项

选项 说明
-a--all 显示所有信息(相当于 -b -d --login -p -r -t -T -u)
-b--boot 显示系统最近启动时间
-d--dead 显示已终止的进程
-H--heading 显示列标题
-l--login 显示系统登录进程
-m 仅显示当前终端相关的用户信息
-p--process 显示由init生成的活动进程
-q--count 显示登录用户总数(快速模式)
-r--runlevel 显示当前运行级别
-s 显示简短信息(默认)
-t--time 显示系统时钟上次修改时间
-T--mesg 显示用户的消息状态(+ 允许,- 禁止)
-u--users 显示已登录用户列表
--version 显示版本信息
--help 显示帮助信息

3. 基本使用示例

3.1 显示当前登录用户(默认)

who

输出示例:

alice    pts/0        2024-01-12 09:30 (192.168.1.100)
bob      tty2         2024-01-12 10:15
charlie  pts/1        2024-01-12 11:00 (192.168.1.101)
输出字段说明:
  • 第一列:登录用户名
  • 第二列:终端设备(tty表示物理终端,pts表示伪终端)
  • 第三列:登录日期和时间
  • 第四列:远程登录的主机名或IP地址(本地登录则空)

3.2 显示详细用户信息

who -uH

输出示例:

名称      线路        时间            空闲    进程号 备注
alice     pts/0       2024-01-12 09:30   .     12345 (192.168.1.100)
bob       tty2        2024-01-12 10:15  01:30  23456
charlie   pts/1       2024-01-12 11:00  00:15  34567 (192.168.1.101)

3.3 显示所有信息

who -aH

显示包括系统启动时间、运行级别等在内的所有信息。

3.4 显示用户消息状态

who -T

输出示例:

alice    + pts/0        2024-01-12 09:30 (192.168.1.100)
bob      - tty2         2024-01-12 10:15
charlie  + pts/1        2024-01-12 11:00 (192.168.1.101)

消息状态说明:+表示允许接收消息,-表示禁止接收消息。

3.5 显示登录用户总数

who -q

输出示例:

alice bob charlie
# 用户数=3

4. 高级使用技巧

4.1 查看特定用户的登录信息

# 查看指定用户的登录信息
who | grep alice

# 查看root用户的登录信息
who | grep '^root'

4.2 查看远程登录用户

# 查看所有远程登录的用户
who | grep -v '(:0)' | grep -v 'tty'

# 或者查看有IP地址的用户
who | awk '{if ($5 != "") print $0}'

4.3 统计用户登录次数

# 统计每个用户的登录次数
who | awk '{print $1}' | sort | uniq -c | sort -rn

# 按用户统计并排序
who | cut -d' ' -f1 | sort | uniq -c | sort -rn

5. 实际应用场景

场景1:系统安全监控

#!/bin/bash
# 系统安全监控脚本:检查异常登录
LOG_FILE="/var/log/user_monitor.log"
ALERT_THRESHOLD=3  # 同一用户最大登录数

echo "=== 用户登录监控报告 $(date) ===" >> $LOG_FILE

# 检查当前登录用户数
USER_COUNT=$(who | wc -l)
echo "当前登录用户数: $USER_COUNT" >> $LOG_FILE

# 检查每个用户的登录次数
echo -e "\n用户登录统计:" >> $LOG_FILE
who | awk '{print $1}' | sort | uniq -c | while read count user; do
    echo "  $user: $count 个会话" >> $LOG_FILE

    # 如果同一用户登录次数过多,发出警告
    if [ $count -gt $ALERT_THRESHOLD ]; then
        echo "警告: 用户 $user 有 $count 个并发会话!" >> $LOG_FILE
        echo "发送警报邮件..."
        echo "用户 $user 有 $count 个并发会话" | mail -s "安全警报: 异常登录" admin@example.com
    fi
done

# 检查远程登录
echo -e "\n远程登录用户:" >> $LOG_FILE
who | awk '$5 ~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ {print $1, $5}' | sort -u >> $LOG_FILE

echo -e "\n监控完成\n" >> $LOG_FILE

场景2:工作时间监控

#!/bin/bash
# 工作时间用户活动监控
REPORT_FILE="/var/log/daily_login_report.txt"
WORK_START="09:00"
WORK_END="18:00"

echo "每日登录报告 - $(date)" > $REPORT_FILE
echo "==========================" >> $REPORT_FILE

# 获取当前时间
CURRENT_HOUR=$(date +%H)
CURRENT_MIN=$(date +%M)
CURRENT_TIME="$CURRENT_HOUR:$CURRENT_MIN"

echo -e "\n1. 当前登录用户 ($CURRENT_TIME):" >> $REPORT_FILE
who -uH >> $REPORT_FILE

echo -e "\n2. 今日登录历史:" >> $REPORT_FILE
last | grep "$(date +'%Y-%m-%d')" | head -20 >> $REPORT_FILE

echo -e "\n3. 工作时间活跃用户统计:" >> $REPORT_FILE
# 这里可以添加更复杂的逻辑来分析用户在岗时间

echo -e "\n报告生成完成" >> $REPORT_FILE
echo "报告已保存到: $REPORT_FILE"

场景3:服务器资源分配

#!/bin/bash
# 基于用户登录情况的资源分配脚本
MIN_USERS=1
MAX_USERS=10
CURRENT_USERS=$(who -q | tail -1 | awk -F= '{print $2}')

echo "当前登录用户数: $CURRENT_USERS"

# 根据用户数调整资源分配
if [ $CURRENT_USERS -lt $MIN_USERS ]; then
    echo "用户数较少,进入节能模式..."
    # 降低CPU频率
    sudo cpupower frequency-set -g powersave
    # 关闭不必要的服务
    sudo systemctl stop unattended-upgrades

elif [ $CURRENT_USERS -gt $MAX_USERS ]; then
    echo "用户数较多,进入高性能模式..."
    # 提高CPU频率
    sudo cpupower frequency-set -g performance
    # 启动额外服务
    sudo systemctl start nginx
    sudo systemctl start mysql

else
    echo "用户数正常,保持当前配置..."
fi

6. 相关命令对比

命令 功能 特点 适用场景
who 显示当前登录用户 简单、快速、信息较少 快速查看谁在线
w 显示登录用户及活动 显示用户正在执行的命令 查看用户当前活动
last 显示登录历史 历史记录、详细时间 审计和调查
lastlog 显示用户最后登录时间 所有用户最后登录时间 检查不活跃账户
users 显示登录用户名 极简、只显示用户名 快速用户计数
finger 显示用户详细信息 用户个人信息、计划等 获取用户完整信息

6.1 命令输出对比示例

# who - 当前登录用户
$ who
alice    pts/0        2024-01-12 09:30 (192.168.1.100)
bob      tty2         2024-01-12 10:15

# w - 用户及活动
$ w
 11:20:15 up 2:30,  2 users,  load average: 0.15, 0.10, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
alice    pts/0    192.168.1.100    09:30    0.00s  0.10s  0.05s sshd: alice [priv]
bob      tty2     -                10:15    1:05m  0.05s  0.05s -bash

# last - 登录历史
$ last | head -5
alice    pts/0        192.168.1.100    Fri Jan 12 09:30   still logged in
bob      tty2                          Fri Jan 12 10:15   still logged in
charlie  pts/1        192.168.1.101    Thu Jan 11 14:20 - 17:45  (03:25)

# lastlog - 最后登录时间
$ lastlog | head -5
用户名           端口     来自             最后登录时间
root                                       **从未登录过**
alice           pts/0    192.168.1.100    五 1月 12 09:30:00 +0800 2024
bob             tty2                      五 1月 12 10:15:00 +0800 2024

7. 数据源和文件

7.1 who命令读取的文件

文件 作用
/var/run/utmp 当前登录用户信息(who命令的主要数据源)
/var/log/wtmp 历史登录记录(last命令的数据源)
/var/log/btmp 失败的登录尝试记录
/proc/self/sessionid 当前会话ID

7.2 直接查看数据文件

# 使用utmpdump查看utmp文件内容
sudo utmpdump /var/run/utmp

# 查看wtmp文件(历史记录)
sudo utmpdump /var/log/wtmp | head -20

# 查看btmp文件(失败登录)
sudo utmpdump /var/log/btmp | head -10

# 统计登录失败次数
sudo utmpdump /var/log/btmp | wc -l

8. 故障排除

问题1:who命令无输出或输出异常

# 检查utmp文件是否存在
ls -la /var/run/utmp

# 检查文件权限
ls -la /var/run/utmp

# 修复utmp文件
sudo touch /var/run/utmp
sudo chmod 664 /var/run/utmp
sudo chown root:utmp /var/run/utmp

# 重启系统服务
sudo systemctl restart systemd-logind

问题2:无法看到所有用户

# 使用-a选项显示所有信息
who -a

# 检查是否使用sudo权限
sudo who -a

# 检查其他登录方式
last
w

# 检查所有伪终端
ls /dev/pts/

问题3:时间显示异常

# 检查系统时区
timedatectl

# 设置正确时区
sudo timedatectl set-timezone Asia/Shanghai

# 检查系统时间
date
hwclock

# 同步时间
sudo ntpdate -u pool.ntp.org

9. 最佳实践

使用建议

  1. 定期监控:定期运行who命令监控系统登录情况
  2. 结合其他命令:与w、last等命令结合使用获取完整信息
  3. 记录日志:重要监控结果应记录日志文件
  4. 设置告警:异常登录情况应设置自动告警
  5. 审计跟踪:定期审计登录记录,发现可疑活动
  6. 权限控制:合理控制用户登录权限
  7. 备份日志:定期备份wtmp、btmp等重要日志文件

9.1 安全监控脚本

#!/bin/bash
# 综合安全监控脚本
LOG_DIR="/var/log/security_monitor"
mkdir -p $LOG_DIR

DAILY_REPORT="$LOG_DIR/daily_report_$(date +%Y%m%d).txt"

echo "=== 每日安全监控报告 ===" > $DAILY_REPORT
echo "生成时间: $(date)" >> $DAILY_REPORT
echo "=========================" >> $DAILY_REPORT

# 1. 当前登录状态
echo -e "\n1. 当前登录用户:" >> $DAILY_REPORT
who -uH >> $DAILY_REPORT

# 2. 今日登录统计
echo -e "\n2. 今日登录统计:" >> $DAILY_REPORT
last | grep "$(date +'%Y-%m-%d')" | wc -l | xargs echo "今日登录次数: " >> $DAILY_REPORT

# 3. 失败登录尝试
echo -e "\n3. 失败登录尝试:" >> $DAILY_REPORT
sudo lastb | head -10 >> $DAILY_REPORT

# 4. 异常登录检测
echo -e "\n4. 异常登录检测:" >> $DAILY_REPORT
# 检测非工作时间登录
CURRENT_HOUR=$(date +%H)
if [ $CURRENT_HOUR -lt 6 ] || [ $CURRENT_HOUR -gt 22 ]; then
    echo "警告: 当前为非工作时间 ($CURRENT_HOUR:00)" >> $DAILY_REPORT
    who >> $DAILY_REPORT
fi

# 5. 用户登录频率
echo -e "\n5. 用户登录频率:" >> $DAILY_REPORT
who | awk '{print $1}' | sort | uniq -c | sort -rn >> $DAILY_REPORT

echo -e "\n报告生成完成" >> $DAILY_REPORT
echo "报告保存至: $DAILY_REPORT"

10. 扩展应用

高级应用场景
1. 实时登录监控面板
#!/bin/bash
# 实时登录监控面板
while true; do
    clear
    echo "=== 实时登录监控面板 ==="
    echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
    echo "========================="
    echo ""

    # 当前登录用户
    echo "当前登录用户:"
    who -uH

    echo ""
    echo "用户活动摘要:"
    w | tail -n +3

    echo ""
    echo "系统状态:"
    echo "运行时间: $(uptime -p)"
    echo "负载: $(uptime | awk -F'load average:' '{print $2}')"

    sleep 5
done
2. 自动化登录审计系统
#!/bin/bash
# 自动化登录审计系统
AUDIT_DB="/var/log/login_audit.db"

# 初始化数据库
if [ ! -f "$AUDIT_DB" ]; then
    echo "创建登录审计数据库..."
    sqlite3 $AUDIT_DB "CREATE TABLE logins (
        id INTEGER PRIMARY KEY,
        username TEXT,
        terminal TEXT,
        login_time TEXT,
        remote_host TEXT,
        session_duration TEXT
    );"
fi

# 收集当前登录信息
collect_logins() {
    who -u | while read line; do
        username=$(echo $line | awk '{print $1}')
        terminal=$(echo $line | awk '{print $2}')
        login_time=$(echo $line | awk '{print $3 " " $4}')
        remote_host=$(echo $line | awk '{print substr($0, index($0,$5))}')

        # 插入数据库
        sqlite3 $AUDIT_DB "INSERT INTO logins (username, terminal, login_time, remote_host)
                          VALUES ('$username', '$terminal', '$login_time', '$remote_host');"
    done
}

# 生成审计报告
generate_report() {
    echo "=== 登录审计报告 ==="
    echo "生成时间: $(date)"
    echo ""

    echo "1. 今日登录统计:"
    sqlite3 $AUDIT_DB "SELECT username, COUNT(*) as count FROM logins
                      WHERE DATE(login_time) = DATE('now')
                      GROUP BY username ORDER BY count DESC;"

    echo ""
    echo "2. 最近登录记录:"
    sqlite3 $AUDIT_DB "SELECT * FROM logins ORDER BY login_time DESC LIMIT 10;"
}

# 执行收集和报告
collect_logins
generate_report
3. 基于登录状态的资源管理
#!/bin/bash
# 基于登录状态的动态资源管理
CONFIG_FILE="/etc/login_based_resources.conf"

# 默认配置
MIN_CPU_FREQ="800MHz"
MAX_CPU_FREQ="3.5GHz"
IDLE_TIMEOUT=1800  # 30分钟

# 监控循环
while true; do
    # 获取当前登录用户数
    USER_COUNT=$(who | wc -l)

    # 获取用户空闲时间
    IDLE_USERS=0
    who -u | awk '{print $5}' | while read idle; do
        if [[ "$idle" =~ ^[0-9]+:[0-9]+$ ]]; then
            # 转换空闲时间为秒
            minutes=$(echo $idle | cut -d: -f1)
            seconds=$(echo $idle | cut -d: -f2)
            total_seconds=$((minutes * 60 + seconds))

            if [ $total_seconds -gt $IDLE_TIMEOUT ]; then
                IDLE_USERS=$((IDLE_USERS + 1))
            fi
        fi
    done

    ACTIVE_USERS=$((USER_COUNT - IDLE_USERS))

    echo "用户状态: 总数=$USER_COUNT, 活跃=$ACTIVE_USERS, 空闲=$IDLE_USERS"

    # 根据活跃用户数调整资源
    if [ $ACTIVE_USERS -eq 0 ]; then
        echo "无活跃用户,进入深度节能模式"
        sudo cpupower frequency-set -d $MIN_CPU_FREQ -u $MIN_CPU_FREQ
        sudo systemctl stop apache2
    elif [ $ACTIVE_USERS -lt 3 ]; then
        echo "少量活跃用户,启用平衡模式"
        sudo cpupower frequency-set -g powersave
    else
        echo "多活跃用户,启用性能模式"
        sudo cpupower frequency-set -g performance
        sudo systemctl start apache2
    fi

    sleep 300  # 每5分钟检查一次
done

实用技巧

  • 使用 who -b 快速查看系统启动时间
  • 结合 watch who 实时监控登录变化
  • 使用 who -q 快速获取用户数用于脚本
  • 通过 who | wc -l 统计在线用户数
  • 使用 lastlastlog 获取历史登录信息
  • 定期清理旧的wtmp和btmp文件避免过大
  • 结合grep和awk对who输出进行高级处理