8.13 找出系统中用户的活动时段

考虑一个使用共享主机(shared hosting)的Web服务器。每天都会有很多用户登录和注销。用户活动都被记入服务器的系统日志。这则攻略是一项实践任务:利用系统日志找出每个用户在服务器上停留了多久,并根据用户的使用时间对他们进行分级,最后生成一份包含等级、用户名、首次登录时间、末次登录时间、登录次数以及总时长等细节信息的报告。让我们看看如何解决这个问题。

8.13.1 新手上路

last命令用来列出一个系统中有关用户登录会话的细节。这些会话数据被存储在/var/log/wtmp文件中。通过分别累计各用户的会话时间,我们就能得出各用户的总使用时间。

8.13.2 实战演练

研究一下这个用来找出活跃用户并生成报告的脚本:

  1. #!/bin/bash
  2. #用户名: active_users.sh
  3. #用途:查找活跃用户
  4. log=/var/log/wtmp
  5. if [[ -n $1 ]];
  6. then
  7. log=$1
  8. fi
  9. printf "%-4s %-10s %-10s %-6s %-8s\n" "Rank" "User" "Start" "Logins"
  10. "Usage hours"
  11. last -f $log | head -n -2 > /tmp/ulog.$$
  12. cat /tmp/ulog.$$ | cut -d' ' -f1 | sort | uniq> /tmp/users.$$
  13. (
  14. while read user;
  15. do
  16. grep ^$user /tmp/ulog.$$ > /tmp/user.$$
  17. seconds=0
  18. while read t
  19. do
  20. s=$(date -d $t +%s 2> /dev/null)
  21. let seconds=seconds+s
  22. done< <(cat /tmp/user.$$ | awk '{ print $NF }' | tr -d ')(')
  23. firstlog=$(tail -n 1 /tmp/user.$$ | awk '{ print $5,$6 }')
  24. nlogins=$(cat /tmp/user.$$ | wc -l)
  25. hours=$(echo "$seconds / 60.0" | bc)
  26. printf "%-10s %-10s %-6s %-8s\n" $user "$firstlog" $nlogins $hours
  27. done< /tmp/users.$$
  28. ) | sort -nrk 4 | awk '{ printf("%-4s %s\n", NR, $0) }'
  29. rm /tmp/users.$$ /tmp/user.$$ /tmp/ulog.$$

样例输出如下:

  1. $ ./active_users.sh
  2. Rank User Start Logins Usage hours
  3. 1 easyibaa Dec 11 531 11437311943
  4. 2 demoproj Dec 10 350 7538718253
  5. 3 kjayaram Dec 9 213 4587849555
  6. 4 cinenews Dec 11 85 1830831769
  7. 5 thebenga Dec 10 54 1163118745
  8. 6 gateway2 Dec 11 52 1120038550
  9. 7 soft132 Dec 12 49 1055420578
  10. 8 sarathla Nov 1 45 969268728
  11. 9 gtsminis Dec 11 41 883107030
  12. 10 agentcde Dec 13 39 840029414

8.13.3 工作原理

在脚本active_users.sh中,我们要提供日志文件wtmp作为命令行参数,也可以使用日志文件defaulwtmp。命令last-f用来打印日志文件的内容。日志文件的第一列是用户名。我们用cut从中提取第一列,然后用sortuniq找出不重复的用户。对每一位用户,用grep找出其对应登录会话的日志行并写入一个临时文件。日志的最后一列是用户登录会话的时长。为了找出用户总的使用时间,需要累加所有的会话时长。使用时间的格式是(小时:秒),因此还需要用date命令将其转换成秒。

要提取用户的会话时长,得使用awk命令。要移除括号,得使用tr -d。用<( COMMANDS )操作符将用户使用时长字符串列表作为标准输入传递给while循环。它的作用就像是文件输入。利用date命令将每一个时长字符串转换成秒数,并累加到变量seconds中。将出现在最后一行的用户的首次登录时间提取出来。登录次数就是日志的行数。要根据总的使用时间来计算每位用户的等级,数据记录需要将总使用时间作为键,进行降序排列。用sort命令的-nr选项指定按照数值逆序排列。-k4指定键的列号(即使用时间)。最后,sort的输出被传递给awkawk命令为每一行添加上行号,这个行号就是每一位用户的等级。