誰常上機?
產生統計資料
last
指令可以查詢最近一段時間, 誰曾經登入系統。
今天我們的任務是統計一下所有人使用這部主機的頻率與時間,
並畫成圖表。
第一部分我們先只統計每人登入的次數。
- 用
last
看一下系統總共有多少人次的登入記錄? - 我們只對本班同學有興趣:
last | perl -ne 'print if /^s4113/'
- 把這部分的結果存起來:
last | perl -ne 'print if /^s4113/' > lastlog.txt
- 我們只對 user name 欄位有興趣:
perl -pe 's/ .*//' < lastlog.txt
- 排序一下, 把同一位使用者的資料集中在一起:
perl -pe 's/ .*//' < lastlog.txt | sort
- 再數一下每個人出現的次數:
perl -pe 's/ .*//' < lastlog.txt | sort | uniq -c
- 按照出現頻率排序, 由多到少:
perl -pe 's/ .*//' < lastlog.txt | sort | uniq -c | sort -nr
- 取前廿名:
perl -pe 's/ .*//' < lastlog.txt | sort | uniq -c | sort -nr | head -20
- 將最後結果存起來:
perl -pe 's/ .*//' < lastlog.txt | sort | uniq -c | sort -nr | head -20 > freq.txt
產生類似這樣的 freq.txt
這裡的 "|" 叫做 pipe, 作用是將前一個指令的輸出,
餵給下一個指令當它的輸入。 如果前一個指令本來就想印到 standard
output 標準輸出裝置, 後一個指令本來就想從 standard input
標準輸入裝置 讀資料, 那麼就可以用 pipe 連接起來。 用白話文講,
如果前一個指令原本要印到螢幕上; 後一個指令原本要 "癡癡地等"
從鍵盤讀資料, 那麼 pipe 的作用正好讓前者的輸出直接變成後者的輸入。
last | perl -pe 's/ .*//'
的效果跟 last >
lastlog.txt ; perl -pe 's/ .*//' < lastlog.txt
兩句合起來的效果一樣; 只不過後者會多產生一個中間過程檔案。
(註: perl -ne 'print if /^s4113/'
與
grep '^s4113'
的效果一樣; 而
perl -pe 's/ .*//'
與 sed
's/ .*//'
的效果一樣。 圖中採用簡寫版本。)
製作圖表
我們將使用 gnuplot 製作圖表。 打
gnuplot
之後, 進入它的環境,
現在開始與我們交談的程式不再是 bash, 而是 gnuplot。 使用 knoppix
光碟或是從 Windows 下用 XLiveCD 連線到學校主機的同學, 應該會看到
"Terminal type set to 'x11'" 的訊息。 從 Windows 下用 telnet 或
putty 連線的同學, 看到的不是 x11 而是 unknown, 這時只好下 set
term dumb
用笨笨的終端機模式畫圖。
gnuplot 跟其他許多文字模式的交談式程式一樣, 也是按 ^d 離開。 先畫幾個簡單的圖, 熟悉一下 gnuplot 的命令:
plot x*x-5
plot sin(x)/x
splot x*x-y*y
plot "freq.txt"
plot "freq.txt" with boxes
help plot
(這篇 help 很長, 裡面有很多子題 subtopcs, 閱讀時請留意下方的訊息。)
我們希望在 x 軸下方標示出 username。
- 先隨便亂實驗一下:
set xtics ("abc" 0, "def" 1, "xyz" 2)
- 要重畫時, 標示才會出現:
replot
- 轉 90 度, 字才不會疊在一起:
set xtics rotate ("abc" 0, "def" 1, "xyz" 2); relpot
- (較新版本的 gnuplot) 如果覺得左下角的滑鼠座標礙眼,
可以叫它不要印:
unset mouse
- 下面好像太擠了。 這是 margin 參數在管的。 先查一下:
show margin
再改適當的設定值:set bmargin 5
再查看一次:show margin
最後重畫:replot
什麼, 要把所有 id 全部用手一個一個敲進去!? 機械化, 重複性的動作,
由人來做, 這樣對嗎? 請開另外一個命令列視窗, 在 bash 底下:
(魔術表演, 暫時不理解沒有關係) perl -ne
'print qq("$1" ) , $.-1 , ",\\\n" if /\d+\s+(\w+)/' freq.txt >
go.gpt
用編輯器進入 go.gpt, 在最上面加上一列 "set
xtics (\" 並將最下面一列尾巴的 ",\" 改成 ")"。 可以猜得出來,
這裡每列最後面的 "\" 表示 "這個指令還沒打完, 但不得已要換列,
請暫時先不要處理"。 回到 gnuplot 視窗, 下 load
"go.gpt"
最後 replot
大功告成。
(圖案看起來有點醜嗎? 上面故意漏了一點東西...請自己修改。)
最後要把圖存檔, 方便日後使用 (例如貼到文件裡面去)。
- 看一下目前的驅動程式:
show term
- 看一下目前的輸出檔名:
show output
- 改採 png 格式輸出:
set term png
- 輸出到 freq.png 檔案裡面去:
set output "freq.png"
- 重畫:
replot
螢幕沒有任何變化; 但家裡多出一個 freq.png 檔。 - 用 file 檢查它的屬性; 用 ee 或 xli 或 xloadimage 看圖。
- 再將輸出切回螢幕, 以免以後畫圖都畫到檔案裡面去,
根本看不見:
set term x11; set output
(若是使用 windows 版, 請將 x11 改成 windows)。
統計登入次數及連線總時數
這一節, 我們的目的是要以每個人登入的次數及連線總分鐘數當做 x-y 座標, 畫出像這樣的圖:
首先計算每人連線總分鐘數: (魔術表演,
暫時不理解沒有關係) perl -ne '$f{$1}+=$2*60+$3 if
/^(\w+).*\((\d\d):(\d\d)\)/ ; END { foreach (keys %f) { printf
"$_:$f{$_}\n"; } }' lastlog.txt > time.txt
接下來在 gnuplot 當中試用一下 set label ...
指令:
set label "good" at 3,1 set label "ok" at 1,3 plot sin(x) plot x*x set xrange [0:5] set yrange [0:5] replot
可以看出: set label 單獨使用並沒有效果, 還是必須等 plot 指令執行後才會出現。 而且 gnuplot 自動調整繪圖範圍的依據, 是 plot 的函數, 而不是 label。 所以必須自己設定 xrange 與 yrange。
所以我們必須從 freq.txt 與 time.txt 產生出 freq-time.gpt。 以下動作, 請自行分解,
把中間過程攔截下來觀察, 不要只管產生結果。 首先調整 freq.txt
兩欄的順序, 把 id 調到前面, 次數放到後面, 並且依 id 排序:
perl -ne 'print "$2:$1\n" if /(\w+)\s+(\w+)/' freq.txt | sort
> a
同樣地, 依 id 為 time.txt 排序: sort time.txt
> b
最後把兩個檔案並排, 並且轉成 gnuplot 的指令:
join -t : a b | perl -ne 'print qq(set label "$1" at $2,$3
center\n) if /(\w+):(\w+):(\w+)/' > freq-time.gpt
然後就可以進入 gnuplot, 開始畫圖:
load "freq-time.gpt" plot 0 set xrange [0:50] set yrange [0:2000] replot
Q: 如何迅速查出 y 的範圍? 一樣用 sort, 不過需要 -t 這個 option。
像這種大部分資料擠在左下角的圖, 如果改用 logscale 畫,
效果會比較好一點。 但要用 logscale, 資料裡面就不可以有 0 或負數。
perl -ne 'print unless /,0 /' freq-time.gpt >
freq-time-nozero.gpt
load "freq-time-nozero.gpt" set logscale set xrange [12:50] set yrange [300:2000] plot 0
提醒: 這篇講義的重點不是統計次數/時間, 而是 如何處理有規律的文字檔以產生統計圖表。 它的應用場合非常廣泛, 不限於此。
- 本頁最新版網址: https://frdm.cyut.edu.tw/~ckhung/b/clr/lastlog.php; 您所看到的版本: February 14 2012 02:32:25.
- 作者: 朝陽科技大學 資訊管理系 洪朝貴
- 寶貝你我的地球, 請 減少列印, 多用背面, 丟棄時做垃圾分類。
- 本文件以 Creative Commons Attribution-ShareAlike License 或以 Free Document License 方式公開授權大眾自由複製/修改/散佈。