Shell脚本开发需求:用户进程定时统计与多维度输出
兄弟,我先帮你把现有代码里的坑指出来,然后给你一个完全满足需求的完整脚本,顺便把每个部分的逻辑讲清楚,你一看就懂:
现有代码的核心问题
- 语法错误:
[ $#2 -gt 0 ]写法完全错了——$#是参数总个数,$2才是第二个参数,正确的写法应该是检查第二个参数是否为正整数,比如[[ "$2" =~ ^[0-9]+$ ]]。 - 逻辑错误:
find $1 ps aux完全驴唇不对马嘴——find是用来找文件的,你要获取进程信息直接用ps aux就行,不需要加find。 - 循环语法错:
while read line true; do写法错误,无限循环的正确姿势是while true; do ... done,read要放在循环内部或者单独处理。 - 需求没覆盖:现有代码完全没实现你要求的「两个统计维度」(过去时间段进程数最多、自启动以来累计进程数最多),也没有写入文件和每分钟定时输出的逻辑。
满足所有需求的完整脚本
#!/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
脚本使用说明
- 参数传入:执行脚本时需要3个参数,比如:
./user_stats.sh ./user_activity.log 10 5- 第一个参数:统计结果写入的文件路径(比如
./user_activity.log) - 第二个参数:写入文件的间隔秒数(比如
10=每10秒写一次) - 第三个参数:每分钟输出的TOP用户数量(比如
5=输出前5个)
- 第一个参数:统计结果写入的文件路径(比如
- 自定义调整:如果需要修改滚动窗口的统计时长(比如改成过去5分钟),直接修改脚本里的
WINDOW_DURATION=300即可。 - 后台运行:如果需要脚本长期后台运行,可以用
nohup:nohup ./user_stats.sh ./user_activity.log 10 5 &
核心逻辑解释
- 累计统计:用临时文件记录每个用户自脚本启动以来的所有进程数总和,每次统计都会累加。
- 滚动窗口统计:记录每条统计的时间戳,定期清理过期数据,保证只统计你指定时间段内的进程数。
- 定时任务:用计数器实现精准的定时触发,避免直接
sleep导致的时间偏差(比如执行统计操作花了2秒,直接sleep 10会变成12秒间隔)。
内容的提问来源于stack exchange,提问作者Aj P.
相关产品推荐
相关产品推荐

