有時候,需要統計每個使用者登入的時間長度。我最開始做這件事情的時候也花費了不少時間。主要是我所用到的伺服器使用者太多,有一千多人,寫好的程式要執行將近半個小時才統計完成。我使用的伺服器是Debian,核心版本為2.6.32
伺服器登入模組採用{PAM+Mysql資料庫的模式,每個使用者都有一個用以分組的屬性,這個屬性是class,我寫的指令碼就是以class來進行分類的。
要統計資料,自然得先有資料來源。Linux中有個檔案存放著所有使用者登入的資訊,就是/var/log/wtmp.這個檔案是二進位檔案,執行last命令,可以看到如下圖的資訊:
上圖中,由於使用者名稱太長,所用可以使用last -w命令來列印出全部使用者名稱。上圖中最後一欄,就是登入的時間長度,我們要做的就是找到相同的使用者名稱,然後將最後一欄的時間長度加起來。
我們的程式最開始可以使用“last -w >> data.file"命令,將資料重新導向到data.file中,然後讀取data.file檔案,分析data.file檔案。
我們可以看到,data.file檔案每行都分為十個段,所以使用:
whie read A B C D E F G H I Jdo 處理代碼done < data.file
如此,變數J就得到了如:(00:00)格式的資料。但是我們需要把資料給分出來,而沒有括弧之類的其他字元。如此我們不得不使用一些常用的工具。在這兒awk是一個非常好的工具:
awk -F 'A' '{print $1}' file
比如上代碼就是將檔案file中的每一行中字元'A'前面的所有資料取出並列印出來,而:
awk -F 'A' '{print $2}' file
是將file檔案中每一行中字元'A'之後的所有資料取出並列印出來。我們要將變數J中的資料取出,我們可以這麼做:
1.先將')'前的所有資料取出;
2.將'('後的資料取出;
3.將':'前的資料取出,這個資料的單位就是小時了;
3.將':'後的資料取出,這個資料的單位就是分鐘了。
參考代碼:
t=$(echo $J | awk -F ')' '{print $1}')p=$(echo $t | awk -F '(' '{print $2}')((hour=10#$(echo $p | awk -F ':' '{print $1}')))((min=10#$(echo $p | awk -F ':' '{print $2}')))
其中,hour、min兩個變數中所使用的"10#",是將資料強制轉換為10進位,而不會是八進位而導致運算錯誤。
現在已經將時、分都取出了,只是再運算即可。如下為My Code,不足之處,因為是臨時寫的代碼,可能有些亂,不足之處,還請指出:
#!/bin/bash############### result file : time_count_file# function : count user login time############### Dir of listDIR_LIST="/home/class/"#data fileDATA_FILE=$(date +%s)_data_file#Result fileRESULT_FILE=count_filelast -w >> $DATA_FILEGain_class=`ls $DIR_LIST | grep 2012`for class in $Gain_classdo if [ ! -d "$DIR_LIST$class/by_id" ];then continue fi echo $class >> $RESULT_FILE for number_student in $(ls "$DIR_LIST$class/by_id") do hour_t=0 min_t=0 Gain_data=`grep $number_student $DATA_FILE` for J in $Gain_data do hour=0 min=0 t=$(echo $J | awk -F ')' '{print $1}') p=$(echo $t | awk -F '(' '{print $2}') ((hour=10#$(echo $p | awk -F ':' '{print $1}'))) ((min=10#$(echo $p | awk -F ':' '{print $2}'))) if [ "$hour" == "" ];then if [ "$min" == "" ];then continue fi fi hour_t=$(($hour_t+$hour)) min_t=$(($min_t+$min)) #echo $hour+$min:$t #echo " "$hour $min >> $RESULT_FILE done if [ $min_t -ge 60 ];then hour_t=$(($hour_t+$min_t/60)) min_t=$(($min_t-($min_t/60)*60)) fi time_he=$((60*$hour_t+$min_t)) echo " ""$number_student time: $time_he" >> $RESULT_FILE donedonerm $DATA_FILE