使用 awk 跟 bash 寫了一隻簡單的 script ,用來分析 squid 產生的 log。不過也發現網路上還滿多分析的工具,但我只需要在 cmd mode 下呈現簡單的資訊,如某個 IP 連線次數、起始時間、最後使用時間,這樣的資訊而以,最後就想到用 awk 能很方便處理,因為 squid log 得格式很簡單,更正確來說,在我的需求面上都很簡單 XD 只要透過 awk 建一個 hash 來記錄 IP 出現的次數、使用時間等,就完成收工了,如:awk '{ if( ip_hash[$3]) ip_hash[$3]++ ; else ip_hash[$3] = 1; } END { for( ip in ip_hash ) print ip , ip_hash[ip]; }' access.log。然而,就突然想要複習一下 bash 提供多一點參數,不小心就跌入萬丈深淵啦,說真的乾脆直接用 Perl、Python 做就好了!不過某總管長輩說,在 FreeBSD 系統預設是沒有裝那種東西的,所以 bash 還是佔有一席之地啊。此程式僅適用於 FreeBSD 系統吧?至少 Ubuntu 因為 date 指令不適用,其他相關筆記:[Unix] 透過指令進行 date 與 timestamp 轉換 @ FreeBSD 和 [Unix] awk 與 bash script 的使用 @ FreeBSD。
此程式接受 3 個參數,必要的 access.log 檔案,兩個次要的參數是 -date 跟 -range ,其中 -date 是指定要從此刻時間分析,而 -range 是與起始時間相距的秒數,可用來限定最多分析到哪個時間點,例如:
- 分析全部記錄:
- # sh slog.sh access.log
- 分析 2011-03-01 起的記錄:
- # sh slog.sh -date "2011-03-01 00:00:00" access.log
- 分析 2011-03-01 到 2011-03-02 之間的記錄:
- # sh slog.sh -date "2011-03-01 00:00:00" -range 86400 access.log
冗長的程式碼:
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage> $0 [-date|-range] file"
echo " -date \"2011-02-14 00:30:40\""
echo " -range \"86400\""
echo
echo "Other Info:"
echo " # date -j -f \"%Y-%m-%d %H:%M:%S\" \"2011-02-14 00:30:40\" \"+%s\""
exit
fi
#date_begin
#date_range
#date_end
#target_file
while [ -n "$1" ]
do
if [ "$1" = "-date" ]; then
shift
if [ -z "$1" ]; then
echo "ERROR: -date BeginDate "
exit
fi
date_begin=$1
elif [ "$1" = "-range" ]; then
shift
if [ -z "$1" ]; then
echo "ERROR: -range Offset"
exit
fi
date_range=$1
else
target_file=$1
fi
shift
done
#
# checking
#
if [ -n "$date_begin" ]; then
echo "[SYS] Data Begin Input: $date_begin"
date_begin=`date -j -f "%Y-%m-%d %H:%M:%S" "$date_begin" "+%s"`
echo "[SYS] Data Begin Timestamp: $date_begin"
fi
if [ -n "$date_range" ]; then
echo "[SYS] Data Range Input: $date_range"
date_end=$(($date_begin+$date_range))
echo "[SYS] Date Begin: $date_begin"
echo "[SYS] Date Finsh: $date_end"
fi
if [ -z "$target_file" ]; then
echo "ERROR: No file"
exit
fi
if [ -f "$target_file" ]; then
else
echo "ERROR: '$target_file' file not exists."
exit
fi
#
# awk profile
#
awk_profile="BEGIN{"
if [ -n "$date_begin" ]; then
awk_profile=$awk_profile"begin_timestamp=$date_begin;"
else
awk_profile=$awk_profile"begin_timestamp=-1;"
fi
if [ -n "$date_end" ]; then
awk_profile=$awk_profile"end_timestamp=$date_end;"
else
awk_profile=$awk_profile"end_timestamp=-1;"
fi
awk_profile=$awk_profile"}\
{\
record_time=\$1;\
record_ip=\$3;\
if((begin_timestamp==-1||record_time>=begin_timestamp)&&(end_timestamp==-1||record_time<=end_timestamp))\
{\
if(ip_hash[record_ip])\
{\
ip_hash[record_ip]++;\
time_end[record_ip]=int(record_time);\
}\
else\
{\
ip_hash[record_ip]=1;\
time_begin[record_ip]=int(record_time);\
time_end[record_ip]=int(record_time);\
}\
}\
}\
END\
{\
printf \"%20s %10s %30s %30s\\n\",\"IP\",\"Count\",\"Begin Time\",\"End Time\";\
for(ip in ip_hash)\
{\
record_time_begin = 0 ; record_time_end = 0 ;\
\"date -j -f \\\"%s\\\" \" time_begin[ip] | getline record_time_begin; close(\"date -j -f \\\"%s\\\" \" time_begin[ip]); \
\"date -j -f \\\"%s\\\" \" time_end[ip] | getline record_time_end; close(\"date -j -f \\\"%s\\\" \" time_end[ip]); \
printf \"%20s,%10d,%30s,%30s\\n\",ip,ip_hash[ip],record_time_begin,record_time_end;\
}\
}"
awk_profile_path=`mktemp -t squid.awk.profile` || exit
awk_output_path=`mktemp -t squid.awk.output` || exit
echo "[SYS] Create awk profile: $awk_profile_path"
echo $awk_profile > $awk_profile_path
#cmd="awk '$awk_profile' \"$target_file\""
cmd="awk -f $awk_profile_path $target_file"
echo "[SYS] Execute: $cmd"
echo "[SYS] Save: $awk_output_path"
`$cmd > $awk_output_path` || exit
echo "[Result]"
cat $awk_output_path
echo
echo "[SYS] Remove logs: rm $awk_profile_path $awk_output_path"
rm $awk_profile_path $awk_output_path
沒有留言:
張貼留言