awkからperlへの移行
awkというと,パターンにマッチした行を処理というのが,お決まりパターンだろうか.これをPerlでやってみる.
awkといえば,とにかく入力をパターンマッチングにかけ,マッチしたパターンに対応する処理を実行するという動きだろうか.
枠組は
何か標準出力 | awk '
/パターン/ {
処理
}'
だろうか.
perlなら
何か標準出力 | perl -e '
foreach (<>) {
if ($_ =~ m/パターン/ ) {
処理
}
}'
何かperlの方が記述が多くなってしまったが,まぁ,awkの本領を発揮するパターンなので(たぶん),ここまではしょうがないとしてたい.
今日のシスログ出力日付を見てみる(面白くするためにsort,uniqしている).
# awk '
/Sep 23/ {
print $3
}' /var/log/syslog | sort| uniq | head
12:18:26
12:18:27
12:18:31
12:18:32
12:18:35
12:19:03
12:19:04
12:19:10
12:38:24
12:49:23
何秒間隔で出力されているだろうか.
# awk '
/Sep 23/ {
split($3, D, ":");
CUR = D[1] * 60 * 60 + D[2] * 60 + D[3]
if(CUR - PRE > 0) {
printf ("%s %d\n", $3, CUR - PRE);
PRE=CUR
}
}' /var/log/syslog | head
12:18:26 44306
12:18:27 1
12:18:31 4
12:18:32 1
12:18:35 3
12:19:03 28
12:19:04 1
12:19:10 6
12:38:24 1154
12:49:23 659
時,分,秒はsplitで分解しているが,perlの正規表現だと,マッチ箇所を()でくくって$1,$2...で指定するだけで簡単に取得できる.
# perl -e '
foreach (<>) {
if ($_ =~ m/Sep 23 ([0-9]+):([0-9]+):([0-9]+) /){
$CUR = $1 * 60 * 60 + $2 * 60 + $3;
if($CUR - $PRE > 0) {
printf ("%s:%s:%s %d\n", $1, $2, $3, $CUR - $PRE);
$PRE=$CUR
}
}
}' /var/log/syslog | head
12:18:26 44306
12:18:27 1
12:18:31 4
12:18:32 1
12:18:35 3
12:19:03 28
12:19:04 1
12:19:10 6
12:38:24 1154
12:49:23 659
awkが6行に対し,perlが6行("}"だけの行はノーカウントで).
awkは年月日やミリ秒が入るとその分split呼び出し(場合によってはsubstrやindex)が増えるが,perlは増えない.
しかも正規表現のマッチ箇所を()で指定するだけなので,直観的なコーディングができる.
というわけで,少なくとも正規表現のマッチング箇所の特定が複雑になるほど,perlの方が楽にコーディングできるような気がする.

