AWK 100行野郎ワールド (AWK hundreds liners) Copyleft 1997-2006 Hiroshi Nakatsukasa http://homepage2.nifty.com/hiroshi-nakatsukasa/ 1998/09/02 私のWebページで使用している、AWKによるCGIスクリプトを公開します。 AWKでもここまで出来るというサンプルとしてご覧ください。 なお、登場するファイル名/ディレクトリ名は架空のものですので、ご了承ください。 (^o^); また、これらのスクリプトを実際に動作させるためには、Webサーバー上への各種設定が 必要となる場合があります。 ▼ 訪問者統計情報を収集する。 ------------------------------ Start of script -------------------------------- #! /usr/bin/awk -f # IP-ADDRの集計を行う。 # (実行環境:UNIX専用) # 1996/12/31 H.Nakatsukasa # # 2006/05/25 ロック関数で使用している UNIX の ln 関数の引数を現代の仕様に変更。 # BEGIN{ debug=0 ### とりあえず画像を表示する。 print "Content-Type: image/gif\n" system("/bin/cat ../dummy.gif") if (lock() != 0) { "date '+%Y'" | getline year close("date '+%Y'") ### 統計情報を収集する。(1) "date '+%y/%m/%d %H:%M:%S'" | getline close("date '+%y/%m/%d %H:%M:%S'") print "\[\[ " $0 " \]\]" >> "statinf.txt" print ENVIRON["REMOTE_HOST"] , "(" ENVIRON["REMOTE_ADDR"] ")" >> "statinf.txt" print ENVIRON["HTTP_USER_AGENT"] >> "statinf.txt" print ENVIRON["HTTP_REFERER"] >> "statinf.txt" print "" >> "statinf.txt" close("statinf.txt") ### 統計情報を収集する。(2) reg_db(ENVIRON["REMOTE_HOST"], "addr.txt") reg_db(year " " ENVIRON["HTTP_USER_AGENT"], "agent.txt") reg_db(ENVIRON["HTTP_REFERER"], "ref.txt") unlock() } else { "date '+%Y'" | getline year close("date '+%Y'") "date '+flt_%y%m%d_%H%M%S'" | getline close("date '+flt_%y%m%d_%H%M%S'") print "\[\[ " $0 " \]\]" > $0 print ENVIRON["REMOTE_HOST"] , "(" ENVIRON["REMOTE_ADDR"] ")" >> $0 print year, ENVIRON["HTTP_USER_AGENT"] >> $0 print ENVIRON["HTTP_REFERER"] >> $0 print "" >> $0 close( $0 ) system("chmod 666 " $0) } exit } ################################################## ## データベースへのレコード登録関数 ## ################################################## function reg_db(keyword,dbfile ,sum,find,f,len) { sum = 0 find = 0 len = length(keyword) printf "" > "addr.tmp" if (debug) {print "keyword = ",keyword,length(keyword),"\n"} ### dbfileの存在チェック。 "ls " dbfile | getline f if (length(f) == 0) { ### dbfileが存在しなければ、ダミーを生成する。 print "" > dbfile close(dbfile) system("chmod 666 " dbfile) if (debug) {print dbfile," is created."} } close("ls " dbfile) ### 既存項目にあれば、カウンタ加算する。 while ( getline < dbfile ) { if ($1 == "Total:") { continue } if ( $0 == (keyword " " $NF) ) { print keyword , $NF+1 >> "addr.tmp" if (debug) {print keyword , $NF+1 , "((match))"} find = 1 sum ++ } else { print >> "addr.tmp" if (debug) {print } } sum = sum + $NF } close(dbfile) ### 新規キーワードなら、最終レコードに追加する。 if (find == 0) { print keyword , 1 >> "addr.tmp" if (debug) {print keyword , 1 , " ((add))"} sum ++ } ### 一応トータル件数を記録する。 print "Total:" , sum >> "addr.tmp" if (debug) {print "Total:" , sum } close("addr.tmp") system("cp addr.tmp " dbfile) system("rm addr.tmp") } ########################################## ## プロセスロック関数 ## ########################################## function lock() { retry = 10 result = 1 # true ### while (system("ln -s lock_image data") != 0) { ### Del 2006/05/25 while (system("ln -s data_g lock_image") != 0) { ### Add 2006/05/25 retry -- if (retry <= 0) { result = 0 # ロック失敗 break } system("sleep 2") } return result } ########################################## ## プロセスロック解除関数 ## ########################################## function unlock() { system("rm lock_image") } # End of file. ------------------------------- End of script --------------------------------- ▼ 訪問者統計情報ファイルおよびその分析結果を表示する。 ------------------------------ Start of script -------------------------------- #! /usr/bin/awk -f # ログの表示を行う。 # # 1997/04/06 H.Nakatsukasa # # 1997/08/15 ホスト名一覧で、カウント数を少なく数えてしまうバグを修正。 # ホスト名の伏せ字部分を増加。 # # 2006/05/25 ロック関数で使用している UNIX の ln 関数の引数を現代の仕様に変更。 # BEGIN{ debug = 0 if ( ENVIRON["COMSPEC"] != "" ) { # PCローカルテスト環境用 envfile = "statinf.txt" awkname = "jgawk" date_yymmdd = "c:\\bin\\date +%y/%m/%d%n" } else { # Web-Server環境用 envfile = "statinf.txt" awkname = "nawk" date_yymmdd = "date +%y/%m/%d%n" } date_yymmdd | getline today close(date_yymmdd) print "Mime-Version: 1.0" print "Content-Type: text/html; charset=Shift_JIS" print "" print "訪問者統計情報一覧" print "
訪問者統計情報一覧

" print "
"
	print "\[\[ アクセス数 \]\]\n"
	dsp_db(envfile)
	print "  (" today " 現在)"
	print "

" print "
"
	print "\[\[ ブラウザの一覧(HTTP_USER_AGENT) \]\]\n"
	system("sort agent.txt | grep -v \"^Total\" ")
	system("grep \"^Total\" agent.txt")
	print "

" print "
"
	print "\[\[ ホスト名の一覧(REMOTE_HOST) \]\]\n"
##	system("sort addr.txt | grep -v \"^Total\" ")	## 旧版 ##
	if (lock("lock_mip") != 0) {
		merge_ip("addr.txt")
		system("sort -f merge_ip.tmp | cut -f2- -d' ' ")
		system("rm merge_ip.tmp")
		unlock("lock_mip")
	} else {
		print "データベースファイルにアクセスできません。"
	}
	system("grep \"^Total\" addr.txt")
	print "

" ## print "
"
##	print "\[\[ HTTP_REFERER \]\]\n"
##	system("sort ref.txt | grep -v \"^Total\" ")
##	print "

" print "
" exit } ##### 関数 ##### ### ### 平均アクセス数の集計を行う。 ### function dsp_db(dbfile ,f,a,t,printformat) { ## 定数 printformat = "%7s : %3dアクセス 平均%5.2fアクセス/日\n" split("31 28 31 30 31 30 31 31 30 31 30 31", DOM, " ") ## 変数 if (debug) {print "dbfile = ",dbfile,"\n"} date_yymmdd | getline today close(date_yymmdd) split(today, t, "\/") todayyymm = t[1] "/" t[2] todaydd = t[3] if (debug) {print today} "ls " dbfile | getline f if (length(f) == 0) { ### dbfileが存在しなければ、終了する。 close("ls " dbfile) return } close("ls " dbfile) while ( getline < dbfile ) { if ( $0 ~ /^\[\[/ ) { split($2, a, "\/") yymm = a[1] "/" a[2] if ( oldyymm == "") { oldyymm = yymm } if ( yymm == oldyymm ) { monthcount ++ } else { oldmm = 0.0 + substr(oldyymm,length(oldyymm)-1,2) if (debug) {printf("%s ",maxday(oldyymm))} # for DEBUG printf(printformat, oldyymm, monthcount, monthcount/maxday(oldyymm) ) oldyymm = yymm monthcount = 1 } } } close(dbfile) if (debug) {printf("%s ",maxday(oldyymm))} # for DEBUG printf(printformat, oldyymm, monthcount, monthcount/maxday(oldyymm) ) } ### ### 指定した月の日数を算出する。 ### 今月なら、今日までの日数。 ### function maxday(date ,result,mm) { if ( date ~ todayyymm ) { result = todaydd } else { mm = 0.0 + substr(date,length(date)-1,2) result = DOM[mm] } return result } ### ### IPアドレス、ドメインネームのアクセス数を集計する。 ### function merge_ip(dbfile ,idx,maxn,kwd) { if (debug) {print "dbfile = ",dbfile,"\n"} if ( (getline f < dbfile) == -1 ) { ### dbfileが存在しなければ、終了する。 if (debug) {print "File not found. (" dbfile ")"} return } if (debug) {print dbfile " detected."} close(dbfile) while ( getline < dbfile ) { if ( $0 ~ /^Total/ ) { ### "Total"文字は削除する。 continue } if ( $0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ / ) { ### IP address sub(/\.[0-9]+\.[0-9]+ /, ".xxx.xxx ") } else { ### Domain name sub(/^[^.]+\./, "xxx.") while ( $0 ~ /\..*\..*\..*\./ ) { sub(/^[^.]+\.[^.]+\./, "xxx.") } } #print $0 ary[ $1 ] += $2 ### 頭文字の分類を行う。 if ($1 !~ /^[0-9]/) { ### Domain name maxn = split($1, dn, /\./) if ($1 ~ /[jJ][pP]$/) { kwd = dn[maxn] "." dn[maxn-1] } else { kwd = dn[maxn] } for (i=1; i "merge_ip.tmp" } close("merge_ip.tmp") } ########################################## ## プロセスロック関数 ## ########################################## function lock(filename) { retry = 10 result = 1 # true ### while (system("ln -s " filename " data") != 0) { ### Del 2006/05/25 while (system("ln -s data_d " filename ) != 0) { ### Add 2006/05/25 retry -- if (retry <= 0) { result = 0 # ロック失敗 break } system("sleep 2") } return result } ########################################## ## プロセスロック解除関数 ## ########################################## function unlock(filename) { system("rm " filename) } # End of file. ------------------------------- End of script --------------------------------- /* End of "awkscript.txt" */