I ♥ WordPress

[時間割:Perl]『ミニマルPerl』その13
2009/01/09 01:44 posted by kunkichi

木曜日は「Perl」です。引き続きAWK編。今回は「パターン範囲」で特定のレコード「群」を抜き出すのをやってみたいと思います。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • AWKでは二つのパターンマッチをカンマで区切って指定すると、最初のパターンにマッチした行から二つ目のパターンにマッチした行までを抜き出すことができる。
    例えばapacheのログから特定の時間帯(例では2008/11/25の1:49:55から1:51:30まで)を抜き出す場合$ awk '/25\/Nov\/2008:01:49:55/ , /25\/Nov\/2008:01:51:30/' access_log.1
    127.0.0.1 - - [25/Nov/2008:01:49:55 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:56 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:57 +0900] "GET / HTTP/1.0" 200 〜
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:51:28 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:29 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:30 +0900] "GET / HTTP/1.0" 200 〜
    Perlの場合は、カンマではなく、範囲演算子 .. で区切る。$ perl -wnl -e '/25\/Nov\/2008:01:49:55/ .. /25\/Nov\/2008:01:51:30/ and print;' access_log.1
  • 範囲演算子には … もある。この場合は2回目のパターンマッチは1回目のパターンマッチが「終わった後」である必要がある。といってもわかりにくいので、例を書いてみる。
    以下のようなテキストデータがあるとする。# cat sample.txt
    Make a Bath on Tuesday
    Take a Bath on Wednesday
    チュラチュラチュラチュラチュラチュララ〜ってやつですねw
    でこれを “Make 〜” で始まって “〜day” で終わるように範囲指定したいとする。
    • ドット2個の場合$ perl -wnl -e '/^Make/ .. /day$/ and print;' sample.txt
      Make a Bath on Tuesday
    • ドット3個の場合$ perl -wnl -e '/^Make/ ... /day$/ and print;' sample.txt
      Make a Bath on Tuesday
      Take a Bath on Wednesday

    つまりドット2個の場合は1回目のパターンと2回目のパターンが同じ行にある場合はそこで終わるけど、ドット3個の場合は1番目のパターンにマッチした「後」の行にマッチするというわけ。ログの調査とかだとドット3個の方が活用するシチュエーションが多い気がする。

  • これにさらにandでパターンマッチを追加する。例えば最初にログの日付でマッチする例をちょっと変えてみて、1:49から1:51のログを抜き出すとする。# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:51/ and print;' access_log.1
    127.0.0.1 - - [25/Nov/2008:01:49:00 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:01 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:02 +0900] "GET / HTTP/1.0" 200 〜
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:50:58 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:50:59 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:00 +0900] "GET / HTTP/1.0" 200 〜
    最後の行を見るとわかると思うけど、このログはほぼ毎秒1回出力されているのに、最後の1:51は0秒のところしか出力されていない。本当はこのあとも1:51:59までこのログが出ている可能性がある。
    ということでちょっと変えてみる。少し先、1:52まで出力してみる。# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:52/ and print;' access_log.1
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:51:58 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:59 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:52:00 +0900] "GET / HTTP/1.0" 200 〜
    うん、やっぱり続いている。
    ということでこれにもう一つパターンマッチを加えてみる。1:52を含まないパターンマッチを追加する。# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:52/ and !/25\/Nov\/2008:01:52/ and print;' access_log.1
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:51:57 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:58 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:59 +0900] "GET / HTTP/1.0" 200 〜
    これでOK。こういう工夫は多少必要だけどわかってしまえばそれほどでもない。
  • 複数の範囲をマッチさせることもできる。たとえば以下のHTMLから<div>〜</div>で囲まれた範囲を抜き出す。$ cat sample.html
    <html>
    <head><title>複数範囲のマッチ</title></head>
    <body>
     
    <div>
    ここが最初のブロック
    </div>
     
    ここは表示されないはず
     
    <div>
    ここが2番目のブロック
    </div>
     
    </body>
    </html>
    $ perl -wnl -e '/^<div>$/ ... /^<\/div>$/ and print;' sample.html
    <div>
    ここが最初のブロック
    </div>
    <div>
    ここが2番目のブロック
    </div>

複数行を範囲で抽出するシチュエーションで本当に多いので、これはかなり使えるかも。

コメント&トラックバック

トラックバックURL





このページの先頭へ