ARAIBOムービーまとめengSearch上田ブログなお、このサイトはbashでできている。半分寝たまま仕事をするのが恒例行事となっております。症状が出るまではつい後回しにしてしまいます。今回の開眼シェルスクリプトはログ捌き後半です。保存した整形済みファイルを使い、端末で有用な情報を抽出します。プログラムで処理するために最適化されていません。シェルスクリプトで処理しやすいように整形します。花粉症も厄介なデータも早めに叩くのが吉¶お題に入る前に、例によって格言を。今回は、次の言葉を意識します。[Pike1989]“データが全てに優先する。適切なデータ構造を選んで物事を整理すれば、アルゴリズムはほとんどの場合に自明となる。アルゴリズムではなく、データ構造がプログラミングの中心である。(Brooksの102ページを見よ。不勉強なため未だ読んでませんが、Brooksの102ページというのは、「人月の神話」の原著の102ページのようです。)要は「データがきれいだとコードが短く簡単になる」ということを言っています。したら、なるべく根元でデータを整形するのが良い習慣と言えるでしょう。どこか適切な場所に整形済みデータを置くことが目標となります。長いシェルスクリプトを涕泗の如く生産して振り回されることになります。・・・花粉症のようになります。今回はデータ整形をシェルスクリプトに残し、雑多な集計を端末で済ませます。定期起動したりCGIスクリプトにしない限りはコードに残すと後で面倒です。扱いやすいデータを生成するという意味で価値が高いので、残す価値があります。前回に引き続き、Linuxのsecureログ、apacheのaccess_logを題材にします。以下のように放り込んであります。secureログが前回執筆時より増えています。secure-20111225まず、恐れ多くも「きれいか汚いか」という観点でログにケチを付けます。プログラムでログを集計しようとすれば以下の点が問題です。secureに西暦年がついていないどちらのログも月の表記が数字でないaccess_logのデータの区切り方が統一されていないこれらを残しておくと、情報を引き出すときに毎回大変な目に遭います。いうことで、ログをきれいにします。大きいプログラムを書け。ログの発生元をカスタマイズするのが最良の方法です。シェルスクリプトで簡潔にします。secureログ整形シェルスクリプト¶まずsecureログから。ログ発生の月日は書いてあっても年が書いてないことです。長期にわたるログの解析や、年をまたいだログのソートができなくなってしまいます。今回はもう少し簡単な方法を使います。年月日が付いているので、これを使ってある日のログファイルに、その日以降のログがあったらそれは前の年のログと決めつけて日付に年をつけます。格言どおり、データ側の都合でアルゴリズムを考える必要が出てきました。最初からログに年情報があればこんなことはしなくてよいのです。いう意味では、過去のログに年月日が付いているので、少し負担は減りました。その代わりに、ポータビリティーは犠牲になります。ログファイルの日付をログに付加する処理をリスト1に示します。8行目で最新のsecureファイルに今日の日付をつけて/tmpにコピーします。理由は後で説明します。下手な排他ではありません。10行目のawk中の「FILENAME」は、ファイル名が入った変数です。10行目の処理で、各ログの先頭にファイル名が入ります。13行目のsedで、ファイル名から日付以外の文字を除去します。「行頭からハイフンでない文字が続いた後にハイフン」という意味です。過去のログ(secure-日付)と同じ処理ができるようにするだけのために行ったものでした。正規化しておいた方がアルゴリズムが簡単になります。速度にこだわる人はシンボリックリンクを使う手もあります。3:ログの内容リスト1のスクリプトを実行すると、出力は次のようになります。pam_unix(su-l:se次にログ自体の日付を正規化していきます。リスト2のスクリプトで、日付を数字にして正規化できます。パイプの部分はawk5個、sed4個で済んでいます。0これで、次の出力のように日付が数字で表現できます。次にaccess_logを整形します。access_logには、左から順に9項目の情報が記述されています。7.転送バイト数、8.参照元サイト、9.クライアントの情報です。ここではawkにあわせて空白区切りのデータにします。その後、日時を8桁6桁に整形します。余計な文字は取り去ります。空白区切りにするところまでの処理をリスト2に示します。sedを使うと以下のようになります。前半の正規表現はレコード全体に一致するように書いてあります。これで、1から9までに各項目が入ります。「でりみた」という文字は、暫定的に区切りにする文字列です。ファイル中に存在する可能性がほぼゼロの文字列ならば何でもかまいません。#「でりみた」という文字を区切り文字にデータを分ける。/g'出力は例えば次のようになります。Mozilla/5.0_(compatible;Baiduspider/2.0;+http://www.baidu.com/search/spider.html)ちゃんと9フィールドになっているか調べるには、awkを使います。NFは、読み込んだレコードのフィールド数が入る変数です。リスト4のようにawkを使って分割する方法があります。ユーザー会の斉藤さんから教えていただいたものです。awkの-Fは、入力の区切り文字を指定するオプションです。この例では「”」を区切り文字に指定しています。$tmp-{1-4,5,6-7,8,9}リスト4のコードで、次の出力のように縦にデータが整理されます。左のコードはレコード番号です。こちらの方が空白も残っていて、自分で区切り文字を作る必要もありません。データは縦でなく横並びになっていた方が楽ちんです。Baiduspider/2.0(略)sed版の続きを作成しましょう。日時を加工する部分を記述します。完成したものをリスト5に示します。コードの部分はたった14行です。ベタに書いて動けば十分です。]、空白を目印にレコードを9分割する。#間延びした区切りの空白を戻す。あとは端末でさっと処理¶では、整形したものから情報を取り出してみましょう。secureログから、不正なユーザでアクセスしてきたIPでも抽出しましょう。user」のレコードを抽出します。下の例のように、headを使って出力を確認しながら書いていきます。一度入力したコマンド列は、bashの場合、上ボタンを押すと再利用できます。泥縄式にコマンドを並べていく場合が多いです。いう方法よりは、さっさと終わります。慣れないうちは、リダイレクトを使ってファイルにデータを貯めて確認しながら練習しましょう。203.236.203.2あとは最後のフィールドのIPアドレスを表示するだけです。(略)今度は、secureログから不正なユーザ名と、使われた回数を表示します。以下は完成したコマンドラインです。ソートされたユーザ名の個数をカウントしています。最後に使用数の多いものから上に並べて上位5個を表示しています。admin次はaccess_logをいじります。一日に何種類のIPアドレスから受信があったかを調べてみましょう。(略)昔はもっとアクセスあったんですが・・・。アクセスランキングでもつくってみましょう。したらリクエストの文字列はもう少し分解したほうが良いかもしれません。どんな拡張子があるか確認してみましょう。cgi、htm、html、phpあたりを対象にしましょう。今回は、ログを整形するシェルスクリプトと端末でのログ集計の例を示しました。今回、forやwhileの使用はゼロでした。if文はawk中で1回だけ使いました。ログに書いてあることは何でも集計できるので、慣れておくと自由が利きます。機会があったら扱ってみたいと考えています。AdSenseやその他ソーシャルボタンのためにCookieを使用しています。同意いただけない場合はブラウザでクッキーを無効にして閲覧をお願いします。