使用 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
沒有留言:
張貼留言