[時間割:Perl]『ミニマルPerl』その13
2009/01/09 01:44 posted by kunkichi
木曜日は「Perl」です。引き続きAWK編。今回は「パターン範囲」で特定のレコード「群」を抜き出すのをやってみたいと思います。
ミニマルPerl Unix/LinuxユーザのためのPerl習得法
posted with amazlet at 08.10.06
Tim Maher
オライリージャパン
売り上げランキング: 96883
オライリージャパン
売り上げランキング: 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.1Perlの場合は、カンマではなく、範囲演算子 .. で区切る。
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 -wnl -e '/25\/Nov\/2008:01:49:55/ .. /25\/Nov\/2008:01:51:30/ and print;' access_log.1 - 範囲演算子には … もある。この場合は2回目のパターンマッチは1回目のパターンマッチが「終わった後」である必要がある。といってもわかりにくいので、例を書いてみる。
以下のようなテキストデータがあるとする。# cat sample.txtチュラチュラチュラチュラチュラチュララ〜ってやつですねw
Make a Bath on Tuesday
Take a Bath on Wednesday
でこれを “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個の方が活用するシチュエーションが多い気がする。
- ドット2個の場合
- これにさらにandでパターンマッチを追加する。例えば最初にログの日付でマッチする例をちょっと変えてみて、1:49から1:51のログを抜き出すとする。
# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:51/ and print;' access_log.1最後の行を見るとわかると思うけど、このログはほぼ毎秒1回出力されているのに、最後の1:51は0秒のところしか出力されていない。本当はこのあとも1:51:59までこのログが出ている可能性がある。
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: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これでOK。こういう工夫は多少必要だけどわかってしまえばそれほどでもない。
・・・
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 〜 - 複数の範囲をマッチさせることもできる。たとえば以下の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: