職場での出来事。
ウチの職場にはいろんな Web サーバがあるのですが、そのうちの一つのコンテンツを管理している部署から「ウチのサイトの月間アクセス数が知りたい」と言われました。でもそのサーバ(ちなみに古い Sun のマシン)には analog の様なアクセス解析ツールは入っていませんでした。Apache HTTP Server の生ログがあるだけの状態。
幸いそんなに詳細なデータが必要でもなさそうだったので、とりあえずサイトのトップページへのリクエスト("GET /" ですね)の回数をもってアクセス数とすることにし、grep を駆使して(といっても2回使っただけですが)当該リクエストのログ行だけを抽出し、最後に wc -l で行数を数えました。
で、とりあえず今年度に入ってからの3ヶ月分を集計して回答したところ、「これから毎月教えてもらいたい」とのご要望が。まぁ、コマンド1行でできることなので毎回コンソール前に行って作業してもたいした手間ではないのですが、定期的に繰り返す作業は自動化したくなるのがパソヲタというもの。よしよし、シェルスクリプトを書いてしんぜよう。
なんせプロンプトでならたった1行のコマンドですから、シェルスクリプトもすぐ書けるだろう、と思ったのが甘かった。
まず grep で検索する文字列は、たとえば先月のログに絞りたかったら 'Jun/2005' の様になります。今月の日付は date コマンドを使えばかなり自由な書式で得ることが出来ますが、cron によってスクリプトを発動するのが毎月1日であることを考えると、date で得られる月と grep で検索したい月は一月ずれます。つまりここで欲しいのは「date で得た月の一月前の月」なのです。
これは単純に引き算で求めるわけにはいかないので、case 文で「date で得たのが "Jul" なら "Jun"、"Aug" なら "Jul"・・・」という処理を12ヶ月分書きました。
さらに、1月1日に発動する分は西暦も減算しないといけません。このスクリプトを何十年も使ったりはしないと思うので、現実的には月の時と同じように1年前の西暦に置き換える処理を向こう数年分列挙してもよかったのですが、やはりせっかく書くからにはそんなダサいコードは書けません。
しかし、Perl ならともかくシェルスクリプトでは引き算をするのも大変です。そのまま変数に引き算できませんから、いったん
echo $YEAR-1 > bc.tmp
echo quit >> bc.tmp
みたいな形で数式をファイルに書き込み、bc bc.tmp を実行して引き算の結果を得る、という面倒なことをしています。
ここまでやってようやく grep をかけて、結果を wc して、行数をファイルに記録して完了です。
なんだかんだで2時間くらいサーバ室にこもってました。
ていうか、Perl で書いた方が早かったかも・・・。と今更思いますが。