[時間割:Perl]『ミニマルPerl』その12
2009/01/06 02:44 posted by kunkichi
三日坊主にならないようにがんばりますw
月曜日は「Perl」です。引き続き、AWKの処理をPerlで実現していきます。今日はAWKの得意なパターンとアクションを組み合わせた処理です。
- AWKの「パターン&アクション」の例
$ awk -F":" '/^root/{ print NR ":" $1 }' /etc/passwdAWKのいいところは、
1:root- アクションを指定していないパターンの場合は、レコードをそのまま自動的に出力する。
$ awk -F":" '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash - パターンを指定していない場合はアクションを全てのレコードに対してそのまま実行する。
$ awk -F":" '{ print NR ":" $1 }' /etc/passwd
1:root
2:bin
3:daemon
4:adm
5:lp
・・・
- アクションを指定していないパターンの場合は、レコードをそのまま自動的に出力する。
- 上記のそれぞれをPerlで実装する。
- パターンとアクション
$ perl -wnlaF":" -e '/^root/ and print "$.:$F[0]";' /etc/passwd
1:root - パターンのみ
$ perl -wnlaF":" -e '/^root/ and print;' /etc/passwdこの場合は明示的にprintをつけないといけない。
root:x:0:0:root:/root:/bin/bash - アクションのみ
$ perl -wnlaF":" -e 'print "$.:$F[0]";' /etc/passwd
1:root
2:bin
3:daemon
4:adm
5:lp
・・・
- パターンとアクション
- AWKのBEGINとENDもそのままPerlで使える。apacheログのファイルサイズの合計と平均を出すサンプルスクリプト。サイズは10番目のフィールド($F[9])に出力されているものとする。
# perl -wnla -e 'BEGINのブロックで変数を初期化しておいて(初期化していない場合は初期化されていないという警告が出る場合があるのと、最終的にデータがなかった場合にENDで出力する際に警告が出て、かつ、NULLになってしまうため。)、ENDでまとめて出力。
> BEGIN{
> $total=0;
> $cnt=0;
> $average=0;
> }
> $total=$total+$F[9];
> $cnt++;
> END{
> $average=$total/$cnt;
> print "TOTAL:$total AVERAGE:$average";
> }' access_log.1
TOTAL:1100250219 AVERAGE:1559 - フィールド処理に対してマッチングするとより細かい条件を設定できる。/etc/passwdの中からUIDが一桁のものを抽出してUIDとユーザ名を出力する。
# perl -wnlaF':' -e '($username, undef, $uid) = @F;$uid =~ /^\d$/ and print "$uid:$username";' /etc/passwd
0:root
1:bin
2:daemon
3:adm
4:lp
5:sync
6:shutdown
7:halt
8:mail
9:news - AWKのNF(最後のフィールド)は、Perlだと$F[-1]。
- 段落モードの場合(-00)は、行単位でフィールド処理を行うのではなく、段落内の全ての文字列に対してフィールド処理が行われる。わかりにくいので以下の例で説明。
例)sarコマンドでCPU使用率を定期的に取得した場合の出力結果は以下。# sar -P ALL -u 1 10※わかりやすいように行番号を入れてますが実際には出力されていません。
1: Linux 2.6.X-X.X.X (www.example.com) 2009年01月06日
2:
3: 02時08分43秒 CPU %user %nice %system %iowait %steal %idle
4: 02時08分44秒 all 0.00 0.00 0.00 0.00 0.00 100.00
5: 02時08分44秒 0 0.00 0.00 0.00 0.00 0.00 100.00
6: 02時08分44秒 1 0.00 0.00 0.00 0.00 0.00 100.00
7:
8: 02時08分44秒 CPU %user %nice %system %iowait %steal %idle
9: 02時08分45秒 all 0.00 0.00 0.00 0.00 0.00 100.00
10: 02時08分45秒 0 0.00 0.00 0.00 0.00 0.00 100.00
11: 02時08分45秒 1 0.00 0.00 0.00 0.00 0.00 100.00
12:
・・・
47:
48: 02時08分52秒 CPU %user %nice %system %iowait %steal %idle
49: 02時08分53秒 all 0.00 0.00 0.00 0.00 0.00 100.00
50: 02時08分53秒 0 0.00 0.00 0.00 0.00 0.00 100.00
51: 02時08分53秒 1 0.00 0.00 0.00 0.00 0.00 100.00
52:
53: 平均値: CPU %user %nice %system %iowait %steal %idle
54: 平均値: all 0.00 0.00 0.00 0.10 0.00 99.90
55: 平均値: 0 0.00 0.00 0.00 0.30 0.00 99.70
56: 平均値: 1 0.00 0.00 0.00 0.00 0.00 100.00このうち、個々のCPU使用率のidle値の推移を取得する。
$ perl -00 -wnla -e '/^¥d/ and print "$F[23] $F[-1]";'ポイントは以下。
100.00 100.00
100.00 100.00
100.00 100.00
100.00 100.00
97.06 100.00
100.00 100.00
100.00 100.00
100.00 100.00
100.00 100.00
100.00 100.00
- 欲しいのは推移データだけなので、1行目のunameの出力と最後のサマリーの段落を出力しないように、段落の最初が数字(sarの個々の出力データは日付が最初に出力されている)の箇所にマッチした段落のみを抽出
- さらに、個々の段落全体の文字列を最初から見ていくと、CPU0のidle値は24番目、CPU1のidle値は32番目なので、それぞれを@Fのインデックス指定で取得。インデックスは0オリジンなので、CPU0のidle値は$F[23]、CPU1のidle値は$F[31]、ただしCPU1のidle値はその段落全体で最後のフィールド最後になるので$F[-1]、として出力。
といった感じで、表データの任意の値だけ取得というのもかんたんにできる。
まあ、こういうデータ抽出をするかどうかは別にして、自分なりの例を作ってやってみると理解しやすい気がしました。次回に続きます。





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