You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell脚本开发需求:用户进程定时统计与多维度输出

兄弟,我先帮你把现有代码里的坑指出来,然后给你一个完全满足需求的完整脚本,顺便把每个部分的逻辑讲清楚,你一看就懂:

现有代码的核心问题

  1. 语法错误:[ $#2 -gt 0 ] 写法完全错了——$# 是参数总个数,$2 才是第二个参数,正确的写法应该是检查第二个参数是否为正整数,比如 [[ "$2" =~ ^[0-9]+$ ]]。
  2. 逻辑错误:find $1 ps aux 完全驴唇不对马嘴——find 是用来找文件的,你要获取进程信息直接用 ps aux 就行,不需要加 find。
  3. 循环语法错:while read line true; do 写法错误,无限循环的正确姿势是 while true; do ... done,read 要放在循环内部或者单独处理。
  4. 需求没覆盖:现有代码完全没实现你要求的「两个统计维度」(过去时间段进程数最多、自启动以来累计进程数最多),也没有写入文件和每分钟定时输出的逻辑。

满足所有需求的完整脚本

#!/bin/bash

# 检查参数合法性
if [ $# -ne 3 ]; then
    echo "用法: $0 <输出文件路径> <写入间隔(秒)> <显示前N个用户>"
    exit 1
fi

OUTPUT_FILE="$1"
INTERVAL="$2"
TOP_N="$3"

# 验证间隔和数量是否为正整数
if ! [[ "$INTERVAL" =~ ^[0-9]+$ ]] || ! [[ "$TOP_N" =~ ^[0-9]+$ ]]; then
    echo "错误: 写入间隔和显示数量必须是正整数"
    exit 1
fi

# 初始化统计临时文件(自启动以来的累计统计)
TOTAL_STATS="/tmp/user_total_stats.tmp"
> "$TOTAL_STATS"

# 初始化滚动窗口统计文件(默认统计过去60秒的进程数,可调整)
WINDOW_STATS="/tmp/user_window_stats.tmp"
> "$WINDOW_STATS"
WINDOW_DURATION=60  # 可修改为你需要的时间段,比如300=5分钟

# 获取当前活跃用户及其进程数
get_current_user_processes() {
    ps aux | awk 'NR>1 {print $1}' | sort | uniq -c | sort -nr
}

# 更新统计数据(累计+滚动窗口)
update_stats() {
    local current_time=$(date +%s)
    # 遍历当前用户进程数,更新两个统计文件
    get_current_user_processes | while read count user; do
        # 更新累计统计:累加用户进程数
        if grep -q "^$user " "$TOTAL_STATS"; then
            local total=$(grep "^$user " "$TOTAL_STATS" | awk '{print $2}')
            total=$((total + count))
            sed -i "/^$user /c\\$user $total" "$TOTAL_STATS"
        else
            echo "$user $count" >> "$TOTAL_STATS"
        fi

        # 更新滚动窗口统计:记录时间戳+用户+进程数
        echo "$current_time $user $count" >> "$WINDOW_STATS"
    done

    # 清理滚动窗口中过期的旧数据(只保留WINDOW_DURATION秒内的记录)
    local cutoff_time=$((current_time - WINDOW_DURATION))
    awk -v cutoff="$cutoff_time" '$1 >= cutoff' "$WINDOW_STATS" > "$WINDOW_STATS.tmp"
    mv "$WINDOW_STATS.tmp" "$WINDOW_STATS"
}

# 将当前活跃用户统计写入指定文件
write_to_file() {
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    echo "=== $timestamp 活跃用户进程统计 ===" >> "$OUTPUT_FILE"
    get_current_user_processes >> "$OUTPUT_FILE"
    echo -e "\n" >> "$OUTPUT_FILE"
}

# 每分钟输出TOP N用户的两个统计维度
print_top_users() {
    echo -e "\n=== $(date "+%Y-%m-%d %H:%M:%S") 统计结果 ==="
    echo "1. 过去$WINDOW_DURATION秒内进程数最多的前$TOP_N个用户:"
    # 统计滚动窗口内的总进程数,排序取前N
    awk '{total[$2] += $3}' "$WINDOW_STATS" | sort -nr -k2 | head -n "$TOP_N" | while read user count; do
        groups=$(id -nG "$user" | tr ' ' ',')
        echo "  用户: $user | 进程数: $count | 所属组: $groups"
    done

    echo -e "\n2. 自脚本启动以来进程数最多的前$TOP_N个用户:"
    # 统计累计进程数,排序取前N
    sort -nr -k2 "$TOTAL_STATS" | head -n "$TOP_N" | while read user count; do
        groups=$(id -nG "$user" | tr ' ' ',')
        echo "  用户: $user | 进程数: $count | 所属组: $groups"
    done
}

# 主循环:同时处理定时写入和每分钟输出
write_counter=0
print_counter=0

while true; do
    # 每INTERVAL秒执行一次统计写入
    if [ $write_counter -eq 0 ]; then
        update_stats
        write_to_file
    fi

    # 每60秒执行一次TOP用户输出
    if [ $print_counter -eq 0 ]; then
        print_top_users
    fi

    # 更新计数器(每秒加1,达到阈值重置)
    write_counter=$(( (write_counter + 1) % INTERVAL ))
    print_counter=$(( (print_counter + 1) % 60 ))

    sleep 1
done

脚本使用说明

  1. 参数传入:执行脚本时需要3个参数,比如:
    ./user_stats.sh ./user_activity.log 10 5
    
    • 第一个参数:统计结果写入的文件路径(比如./user_activity.log)
    • 第二个参数:写入文件的间隔秒数(比如10=每10秒写一次)
    • 第三个参数:每分钟输出的TOP用户数量(比如5=输出前5个)
  2. 自定义调整:如果需要修改滚动窗口的统计时长(比如改成过去5分钟),直接修改脚本里的WINDOW_DURATION=300即可。
  3. 后台运行:如果需要脚本长期后台运行,可以用nohup:
    nohup ./user_stats.sh ./user_activity.log 10 5 &
    

核心逻辑解释

  • 累计统计:用临时文件记录每个用户自脚本启动以来的所有进程数总和,每次统计都会累加。
  • 滚动窗口统计:记录每条统计的时间戳,定期清理过期数据,保证只统计你指定时间段内的进程数。
  • 定时任务:用计数器实现精准的定时触发,避免直接sleep导致的时间偏差(比如执行统计操作花了2秒,直接sleep 10会变成12秒间隔)。

内容的提问来源于stack exchange,提问作者Aj P.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:28:32