ファイヤープロジェクト
awkからperlへの移行
2007-09-23T22:00+09:00   matsu
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の方が楽にコーディングできるような気がする.
matsu(C)
Since 2002
Mail to matsu